1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <string.h>
15 #include "esp_attr.h"
16 #include "esp_partition.h"
17 #include "esp_ota_ops.h"
18 #include "esp_spi_flash.h"
19 #include "esp_flash_encrypt.h"
20 #include "sdkconfig.h"
21 #include "core_dump_checksum.h"
22 #include "core_dump_elf.h"
23 #include "esp_core_dump_port.h"
24 #include "esp_core_dump_port_impl.h"
25 #include "esp_core_dump_common.h"
26 
27 #define ELF_CLASS ELFCLASS32
28 
29 #include "elf.h"                    // for ELF file types
30 
31 #define ELF_SEG_HEADERS_COUNT(_self_) ((_self_)->segs_count)
32 
33 #define ELF_HLEN 52
34 #define ELF_CORE_SEC_TYPE 1
35 #define ELF_PR_STATUS_SEG_NUM 0
36 #define ELF_ESP_CORE_DUMP_INFO_TYPE 8266
37 #define ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE 677
38 #define ELF_NOTE_NAME_MAX_SIZE 32
39 #define ELF_APP_SHA256_SIZE 66
40 
41 #define ELF_CHECK_ERR(a, ret_val, str, ...) \
42     if (!(a)) { \
43         ESP_COREDUMP_LOGE("%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
44         return (ret_val); \
45     }
46 
47 typedef enum
48 {
49     ELF_STAGE_CALC_SPACE = 0,
50     ELF_STAGE_PLACE_HEADERS = 1,
51     ELF_STAGE_PLACE_DATA = 2
52 } core_dump_elf_stages_t;
53 
54 typedef enum _elf_err_t
55 {
56     ELF_PROC_ERR_SKIP_HEADER = 0,
57     ELF_PROC_ERR_STACK_CORRUPTED = -1,
58     ELF_PROC_ERR_WRITE_FAIL = -2,
59     ELF_PROC_ERR_OTHER = -3
60 } core_dump_elf_proc_err_t;
61 
62 typedef struct _core_dump_task_info_t
63 {
64     elf_phdr* phdr;
65     void* frame;
66     core_dump_task_header_t* task_hdr;
67     uint32_t task_id;
68     size_t tcb_sz;
69     int* size_ptr;
70 } core_dump_task_data_t;
71 
72 typedef struct
73 {
74     uint32_t version; // coredump version
75     uint8_t app_elf_sha256[ELF_APP_SHA256_SIZE]; // sha256 of elf file
76 } core_dump_elf_version_info_t;
77 
78 const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_elf";
79 
80 // Main ELF handle type
81 typedef struct _core_dump_elf_t
82 {
83     core_dump_elf_version_info_t    elf_version_info;
84     uint16_t                        elf_stage;
85     uint32_t                        elf_next_data_offset;
86     uint16_t                        segs_count;
87     core_dump_write_config_t *      write_cfg;
88 } core_dump_elf_t;
89 
90 // Represents lightweight implementation to save core dump data into ELF formatted binary
91 
92 #define ALIGN(b, var) var = align(b, var)
93 
94 #if CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
95 
align(uint32_t width,uint32_t in)96 static inline uint32_t align(uint32_t width, uint32_t in)
97 {
98   return (in + (width - 1)) & -width;
99 }
100 
101 // Builds elf header and check all data offsets
elf_write_file_header(core_dump_elf_t * self,uint32_t seg_count)102 static int elf_write_file_header(core_dump_elf_t *self, uint32_t seg_count)
103 {
104     elfhdr elf_hdr; // declare as static to save stack space
105 
106     if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
107         ESP_COREDUMP_LOG_PROCESS("Segment count %u", seg_count);
108         memset(&elf_hdr, 0, sizeof(elfhdr));
109         elf_hdr.e_ident[0] = ELFMAG0;
110         elf_hdr.e_ident[1] = ELFMAG1;
111         elf_hdr.e_ident[2] = ELFMAG2;
112         elf_hdr.e_ident[3] = ELFMAG3;
113         elf_hdr.e_ident[4] = ELFCLASS32;
114         elf_hdr.e_ident[5] = ELFDATA2LSB;
115         elf_hdr.e_ident[6] = EV_CURRENT;
116         elf_hdr.e_ident[7] = ELFOSABI_NONE;
117         elf_hdr.e_ident[8] = 0;
118         elf_hdr.e_type = ET_CORE;
119         elf_hdr.e_machine = esp_core_dump_get_arch_id();
120         elf_hdr.e_flags = 0;
121         elf_hdr.e_version = EV_CURRENT;
122         elf_hdr.e_entry = 0;
123         _Static_assert(sizeof(elfhdr) == ELF_HLEN, "Invalid ELF header struct length!");
124         elf_hdr.e_phoff = sizeof(elfhdr);          // program header table's file offset in bytes.
125         elf_hdr.e_phentsize = sizeof(elf_phdr);    // size in bytes of one entry in the file program header table
126         elf_hdr.e_phnum = seg_count;                 // number of program segments
127         elf_hdr.e_shoff = 0;                       // section header table's file offset in bytes.
128         elf_hdr.e_ehsize = sizeof(elfhdr);         // elf header size
129         elf_hdr.e_shentsize = sizeof(elf_shdr);    // section header's size in bytes.
130         elf_hdr.e_shnum = 0;                       // initial section counter is 0
131         elf_hdr.e_shstrndx = SHN_UNDEF;            // do not use string table
132         // write built elf header into elf image
133         esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)&elf_hdr, sizeof(elf_hdr));
134         ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
135                         "Write ELF header failure (%d)", err);
136         ESP_COREDUMP_LOG_PROCESS("Add file header %u bytes", sizeof(elf_hdr));
137     }
138 
139     return self->elf_stage == ELF_STAGE_PLACE_DATA ? 0 : sizeof(elf_hdr);
140 }
141 
elf_write_segment_header(core_dump_elf_t * self,elf_phdr * phdr)142 static int elf_write_segment_header(core_dump_elf_t *self, elf_phdr* phdr)
143 {
144     ELF_CHECK_ERR(phdr, ELF_PROC_ERR_SKIP_HEADER,
145                     "Header is skipped, stage=(%d).", self->elf_stage);
146 
147     phdr->p_offset = self->elf_next_data_offset;
148     // set segment data information and write it into image
149     esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)phdr, sizeof(elf_phdr));
150     ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
151                     "Write ELF segment header failure (%d)", err);
152     ESP_COREDUMP_LOG_PROCESS("Add segment header %u bytes: type %d, sz %u, off = 0x%x",
153                             sizeof(elf_phdr), phdr->p_type, phdr->p_filesz, phdr->p_offset);
154 
155     return sizeof(elf_phdr);
156 }
157 
elf_add_segment(core_dump_elf_t * self,uint32_t type,uint32_t vaddr,void * data,uint32_t data_sz)158 static int elf_add_segment(core_dump_elf_t *self,
159                             uint32_t type, uint32_t vaddr,
160                             void* data, uint32_t data_sz)
161 {
162     esp_err_t err = ESP_FAIL;
163     elf_phdr seg_hdr = { 0 };
164     int data_len = data_sz;
165 
166     ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
167                 "Invalid data for segment.");
168 
169     ALIGN(4, data_len);
170 
171     if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
172         self->segs_count++;
173         return data_len + sizeof(elf_phdr);
174     }
175     if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
176         seg_hdr.p_type = type;
177         seg_hdr.p_vaddr = vaddr;
178         seg_hdr.p_paddr = vaddr;
179         seg_hdr.p_filesz = data_len;
180         seg_hdr.p_memsz = data_len;
181         seg_hdr.p_flags = (PF_R | PF_W);
182         int ret = elf_write_segment_header(self, &seg_hdr);
183         ELF_CHECK_ERR((ret > 0), ret,
184                         "Write ELF segment data failure (%d)", ret);
185         self->elf_next_data_offset += data_len;
186         return ret;
187     }
188     ESP_COREDUMP_LOG_PROCESS("Add segment size=%u, start_off=0x%x",
189                                 (uint32_t)data_len, self->elf_next_data_offset);
190     // write segment data only when write function is set and phdr = NULL
191     // write data into segment
192     err = self->write_cfg->write(self->write_cfg->priv, data, (uint32_t)data_len);
193     ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
194                     "Write ELF segment data failure (%d)", err);
195     self->elf_next_data_offset += data_len;
196     return data_len;
197 }
198 
elf_write_note(core_dump_elf_t * self,const char * name,uint32_t type,void * data,uint32_t data_sz)199 static int elf_write_note(core_dump_elf_t *self,
200                             const char* name,
201                             uint32_t type,
202                             void* data,
203                             uint32_t data_sz)
204 {
205     esp_err_t err = ESP_FAIL;
206     // temporary buffer for note name
207     static char name_buffer[ELF_NOTE_NAME_MAX_SIZE] = { 0 };
208     elf_note note_hdr = { 0 };
209     uint32_t name_len = strlen(name) + 1; // get name length including terminator
210     uint32_t data_len = data_sz;
211 
212     ELF_CHECK_ERR(data, ELF_PROC_ERR_OTHER,
213             "Invalid data pointer %x.", (uint32_t)data);
214     ELF_CHECK_ERR((name_len <= ELF_NOTE_NAME_MAX_SIZE), 0,
215                 "Segment note name is too long %d.", name_len);
216 
217     ALIGN(4, data_len);
218     ALIGN(4, name_len);
219     uint32_t note_size = name_len + data_len + sizeof(elf_note);
220     ALIGN(4, note_size);
221 
222     // write segment data during second pass
223     if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
224         memcpy((void*)name_buffer, (void*)name, name_len);
225         note_hdr.n_namesz = name_len;
226         note_hdr.n_descsz = data_sz;
227         note_hdr.n_type = type;
228         // write note header
229         err = self->write_cfg->write(self->write_cfg->priv, (void*)&note_hdr, sizeof(note_hdr));
230         ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
231                 "Write ELF note header failure (%d)", err);
232         // write note name
233         err = self->write_cfg->write(self->write_cfg->priv, (void*)name_buffer, name_len);
234         ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
235                         "Write ELF note name failure (%d)", err);
236         // write note data
237         err = self->write_cfg->write(self->write_cfg->priv, (void*)data, data_len);
238         ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
239                         "Write ELF note data failure (%d)", err);
240         ESP_COREDUMP_LOG_PROCESS("Add note size=%d, start_off=0x%x",
241                                     note_size, self->elf_next_data_offset);
242     }
243     return note_size; // return actual note size
244 }
245 
elf_add_note(core_dump_elf_t * self,const char * name,uint32_t type,void * data,uint32_t data_sz)246 static int elf_add_note(core_dump_elf_t *self,
247                         const char* name,
248                         uint32_t type,
249                         void* data,
250                         uint32_t data_sz)
251 {
252     ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
253             "Invalid data pointer for segment");
254 
255     int note_size = elf_write_note(self, name, type, data, data_sz);
256     ELF_CHECK_ERR((note_size > 0), note_size,
257                     "Write ELF note data failure, returned (%d)", note_size);
258     return note_size; // return actual note segment size
259 }
260 
261 // Append note with registers dump to segment note
elf_add_regs(core_dump_elf_t * self,core_dump_task_header_t * task)262 static int elf_add_regs(core_dump_elf_t *self, core_dump_task_header_t *task)
263 {
264     void *reg_dump;
265 
266     uint32_t len = esp_core_dump_get_task_regs_dump(task, &reg_dump);
267     if (len == 0) {
268         ESP_COREDUMP_LOGE("Zero size register dump for task 0x%x!", task->tcb_addr);
269         return ELF_PROC_ERR_OTHER;
270     }
271 
272     // append note data with dump to existing note
273     return elf_add_note(self,
274                         "CORE",                // note name
275                         ELF_CORE_SEC_TYPE,     // note type for reg dump
276                         reg_dump,      // register dump with pr_status
277                         len);
278 }
279 
elf_add_stack(core_dump_elf_t * self,core_dump_task_header_t * task)280 static int elf_add_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
281 {
282     uint32_t stack_vaddr, stack_len = 0, stack_paddr = 0;
283 
284     ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
285 
286     stack_len = esp_core_dump_get_stack(task, &stack_vaddr, &stack_paddr);
287     ESP_COREDUMP_LOG_PROCESS("Add stack for task 0x%x: addr 0x%x, sz %u",
288                                 task->tcb_addr, stack_vaddr, stack_len);
289     int ret = elf_add_segment(self, PT_LOAD,
290                                 (uint32_t)stack_vaddr,
291                                 (void*)stack_paddr,
292                                 (uint32_t) stack_len);
293     return ret;
294 }
295 
elf_add_tcb(core_dump_elf_t * self,core_dump_task_header_t * task)296 static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
297 {
298     ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
299     // add task tcb data into program segment of ELF
300     ESP_COREDUMP_LOG_PROCESS("Add TCB for task 0x%x: addr 0x%x, sz %u",
301                                 task->tcb_addr, task->tcb_addr,
302                                 esp_core_dump_get_tcb_len());
303     int ret = elf_add_segment(self, PT_LOAD,
304                                 (uint32_t)task->tcb_addr,
305                                 task->tcb_addr,
306                                 esp_core_dump_get_tcb_len());
307     return ret;
308 }
309 
elf_process_task_tcb(core_dump_elf_t * self,core_dump_task_header_t * task)310 static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
311 {
312     int ret = ELF_PROC_ERR_OTHER;
313 
314     ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
315 
316     // save tcb of the task as is and apply segment size
317     ret = elf_add_tcb(self, task);
318     if (ret <= 0) {
319         ESP_COREDUMP_LOGE("Task (TCB:%x) processing failure = %d",
320                                             task->tcb_addr,
321                                             ret);
322     }
323     return ret;
324 }
325 
elf_process_task_stack(core_dump_elf_t * self,core_dump_task_header_t * task)326 static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
327 {
328     int ret = ELF_PROC_ERR_OTHER;
329 
330     ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
331 
332     ret = elf_add_stack(self, task);
333     if (ret <= 0) {
334         ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
335                                     task->tcb_addr,
336                                     task->stack_start,
337                                     ret);
338     }
339     return ret;
340 }
341 
elf_process_note_segment(core_dump_elf_t * self,int notes_size)342 static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
343 {
344     int ret;
345     elf_phdr seg_hdr = { 0 };
346 
347     if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
348         // segment header for PR_STATUS notes
349         seg_hdr.p_type = PT_NOTE;
350         seg_hdr.p_vaddr = 0;
351         seg_hdr.p_paddr = 0;
352         seg_hdr.p_filesz = notes_size;
353         seg_hdr.p_memsz = notes_size;
354         seg_hdr.p_flags = (PF_R | PF_W);
355         ret = elf_write_segment_header(self, &seg_hdr);
356         ELF_CHECK_ERR((ret > 0), ret, "NOTE segment header write failure, returned (%d).", ret);
357         self->elf_next_data_offset += notes_size;
358         return sizeof(seg_hdr);
359     } else if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
360         self->segs_count++;
361         notes_size += sizeof(seg_hdr);
362     } else {
363         // in "Place Data" phase segment body is been already filled by other functions
364         ESP_COREDUMP_LOG_PROCESS("Add NOTE segment, size=%d, start_off=0x%x",
365                                     notes_size, self->elf_next_data_offset);
366         self->elf_next_data_offset += notes_size;
367     }
368     return (int)notes_size;
369 }
370 
elf_process_tasks_regs(core_dump_elf_t * self)371 static int elf_process_tasks_regs(core_dump_elf_t *self)
372 {
373     core_dump_task_header_t task_hdr = { 0 };
374     void *task = NULL;
375     int len = 0;
376     int ret = 0;
377 
378     esp_core_dump_reset_tasks_snapshots_iter();
379     task = esp_core_dump_get_current_task_handle();
380     if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
381         // place current task dump first
382         ret = elf_add_regs(self,  &task_hdr);
383         if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
384             // when writing segments headers this function writes nothing
385             ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
386         } else {
387             ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
388         }
389         len += ret;
390     }
391     // processes PR_STATUS and register dump for each task
392     // each call to the processing function appends PR_STATUS note into note segment
393     // and writes data or updates the segment note header accordingly (if phdr is set)
394     task = NULL;
395     while ((task = esp_core_dump_get_next_task(task))) {
396         if (task == esp_core_dump_get_current_task_handle()) {
397             continue; // skip current task (already processed)
398         }
399         if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
400             ret = elf_add_regs(self,  &task_hdr);
401             if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
402                 // when writing segments headers this function writes nothing
403                 ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
404             } else {
405                 ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
406             }
407             len += ret;
408         }
409     }
410     ret = elf_process_note_segment(self, len); // tasks regs note
411     ELF_CHECK_ERR((ret > 0), ret,
412                     "PR_STATUS note segment processing failure, returned(%d).", ret);
413     return ret;
414 }
415 
elf_save_task(core_dump_elf_t * self,core_dump_task_header_t * task)416 static int elf_save_task(core_dump_elf_t *self, core_dump_task_header_t *task)
417 {
418     int elf_len = 0;
419 
420     int ret = elf_process_task_tcb(self, task);
421     ELF_CHECK_ERR((ret > 0), ret,
422                     "Task %x, TCB write failed, return (%d).", task->tcb_addr, ret);
423     elf_len += ret;
424     ret = elf_process_task_stack(self, task);
425     ELF_CHECK_ERR((ret != ELF_PROC_ERR_WRITE_FAIL), ELF_PROC_ERR_WRITE_FAIL,
426                     "Task %x, stack write failed, return (%d).", task->tcb_addr, ret);
427     elf_len += ret;
428     return elf_len;
429 }
430 
elf_write_tasks_data(core_dump_elf_t * self)431 static int elf_write_tasks_data(core_dump_elf_t *self)
432 {
433     int elf_len = 0;
434     void *task = NULL;
435     core_dump_task_header_t task_hdr = { 0 };
436     core_dump_mem_seg_header_t interrupted_stack = { 0 };
437     int ret = ELF_PROC_ERR_OTHER;
438     uint16_t tasks_num = 0;
439     uint16_t bad_tasks_num = 0;
440 
441     ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================");
442     ret = elf_process_tasks_regs(self);
443     ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
444     elf_len += ret;
445 
446     ESP_COREDUMP_LOG_PROCESS("================   Processing task data   ================");
447     // processes all task's stack data and writes segment data into partition
448     // if flash configuration is set
449     task = NULL;
450     esp_core_dump_reset_tasks_snapshots_iter();
451     while ((task = esp_core_dump_get_next_task(task))) {
452         tasks_num++;
453         if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &interrupted_stack)) {
454             bad_tasks_num++;
455             continue;
456         }
457         ret = elf_save_task(self, &task_hdr);
458         ELF_CHECK_ERR((ret > 0), ret,
459                         "Task %x, TCB write failed, return (%d).", task, ret);
460         elf_len += ret;
461         if (interrupted_stack.size > 0) {
462             ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x",
463                     interrupted_stack.size, interrupted_stack.start);
464             ret = elf_add_segment(self, PT_LOAD,
465                                     (uint32_t)interrupted_stack.start,
466                                     (void*)interrupted_stack.start,
467                                     (uint32_t)interrupted_stack.size);
468             ELF_CHECK_ERR((ret > 0), ret, "Interrupted task stack write failed, return (%d).", ret);
469             elf_len += ret;
470         }
471     }
472     ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num);
473     return elf_len;
474 }
475 
elf_write_core_dump_user_data(core_dump_elf_t * self)476 static int elf_write_core_dump_user_data(core_dump_elf_t *self)
477 {
478     int data_len = 0;
479     int total_sz = 0;
480     uint32_t start = 0;
481 
482     for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
483         data_len = esp_core_dump_get_user_ram_info(i, &start);
484 
485         ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region");
486 
487         if (data_len > 0) {
488             int ret = elf_add_segment(self, PT_LOAD,
489                         (uint32_t)start,
490                         (void*)start,
491                         (uint32_t) data_len);
492 
493             ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret);
494             total_sz += ret;
495         }
496     }
497 
498     return total_sz;
499 }
500 
elf_write_core_dump_info(core_dump_elf_t * self)501 static int elf_write_core_dump_info(core_dump_elf_t *self)
502 {
503     void *extra_info = NULL;
504 
505     ESP_COREDUMP_LOG_PROCESS("================ Processing coredump info ================");
506     int data_len = (int)sizeof(self->elf_version_info.app_elf_sha256);
507     data_len = esp_ota_get_app_elf_sha256((char*)self->elf_version_info.app_elf_sha256, (size_t)data_len);
508     ESP_COREDUMP_LOG_PROCESS("Application SHA256='%s', length=%d.",
509                                 self->elf_version_info.app_elf_sha256, data_len);
510     self->elf_version_info.version = esp_core_dump_elf_version();
511     int ret = elf_add_note(self,
512                             "ESP_CORE_DUMP_INFO",
513                             ELF_ESP_CORE_DUMP_INFO_TYPE,
514                             &self->elf_version_info,
515                             sizeof(self->elf_version_info));
516     ELF_CHECK_ERR((ret > 0), ret, "Version info note write failed. Returned (%d).", ret);
517     data_len = ret;
518 
519     uint32_t extra_info_len = esp_core_dump_get_extra_info(&extra_info);
520     if (extra_info_len == 0) {
521         ESP_COREDUMP_LOGE("Zero size extra info!");
522         return ELF_PROC_ERR_OTHER;
523     }
524 
525     ret = elf_add_note(self,
526                         "EXTRA_INFO",
527                         ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE,
528                         extra_info,
529                         extra_info_len);
530     ELF_CHECK_ERR((ret > 0), ret, "Extra info note write failed. Returned (%d).", ret);
531     data_len += ret;
532 
533     ret = elf_process_note_segment(self, data_len);
534     ELF_CHECK_ERR((ret > 0), ret,
535                     "EXTRA_INFO note segment processing failure, returned(%d).", ret);
536     return ret;
537 }
538 
esp_core_dump_do_write_elf_pass(core_dump_elf_t * self)539 static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self)
540 {
541     int tot_len = 0;
542 
543     int data_sz = elf_write_file_header(self, ELF_SEG_HEADERS_COUNT(self));
544     if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
545         ELF_CHECK_ERR((data_sz >= 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
546     } else {
547         ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
548     }
549     tot_len += data_sz;
550     // Calculate whole size include headers for all tasks and main elf header
551     data_sz = elf_write_tasks_data(self);
552     ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
553     tot_len += data_sz;
554 
555     // write core dump memory regions defined by user
556     data_sz = elf_write_core_dump_user_data(self);
557     ELF_CHECK_ERR((data_sz >= 0), data_sz, "memory regions writing error, returned (%d).", data_sz);
558     tot_len += data_sz;
559 
560     // write data with version control information and some extra info
561     // this should go after tasks processing
562     data_sz = elf_write_core_dump_info(self);
563     ELF_CHECK_ERR((data_sz > 0), data_sz, "Version info writing failed. Returned (%d).", data_sz);
564     tot_len += data_sz;
565 
566     return tot_len;
567 }
568 
esp_core_dump_write_elf(core_dump_write_config_t * write_cfg)569 esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg)
570 {
571     static core_dump_elf_t self = { 0 };
572     static core_dump_header_t dump_hdr = { 0 };
573     esp_err_t err = ESP_OK;
574     int tot_len = sizeof(dump_hdr);
575     int write_len = sizeof(dump_hdr);
576 
577     ELF_CHECK_ERR((write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
578 
579     self.write_cfg = write_cfg;
580 
581     // On first pass (do not write actual data), but calculate data length needed to allocate memory
582     self.elf_stage = ELF_STAGE_CALC_SPACE;
583     ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
584     int ret = esp_core_dump_do_write_elf_pass(&self);
585     if (ret < 0) return ret;
586     tot_len += ret;
587     ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu", tot_len);
588     ESP_COREDUMP_LOG_PROCESS("============== Data size = %d bytes ============", tot_len);
589 
590     // Prepare write elf
591     if (write_cfg->prepare) {
592         err = write_cfg->prepare(write_cfg->priv, (uint32_t*)&tot_len);
593         if (err != ESP_OK) {
594             ESP_COREDUMP_LOGE("Failed to prepare core dump storage (%d)!", err);
595             return err;
596         }
597     }
598 
599     // Write start
600     if (write_cfg->start) {
601         err = write_cfg->start(write_cfg->priv);
602         if (err != ESP_OK) {
603             ESP_COREDUMP_LOGE("Failed to start core dump (%d)!", err);
604             return err;
605         }
606     }
607 
608     // Write core dump header
609     dump_hdr.data_len = tot_len;
610     dump_hdr.version = esp_core_dump_elf_version();
611     dump_hdr.tasks_num = 0; // unused in ELF format
612     dump_hdr.tcb_sz = 0; // unused in ELF format
613     dump_hdr.mem_segs_num = 0; // unused in ELF format
614     err = write_cfg->write(write_cfg->priv,
615                            (void*)&dump_hdr,
616                            sizeof(core_dump_header_t));
617     if (err != ESP_OK) {
618         ESP_COREDUMP_LOGE("Failed to write core dump header (%d)!", err);
619         return err;
620     }
621 
622     self.elf_stage = ELF_STAGE_PLACE_HEADERS;
623     // set initial offset to elf segments data area
624     self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
625     ret = esp_core_dump_do_write_elf_pass(&self);
626     if (ret < 0) return ret;
627     write_len += ret;
628     ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
629 
630     self.elf_stage = ELF_STAGE_PLACE_DATA;
631     // set initial offset to elf segments data area, this is not necessary in this stage, just for pretty debug output
632     self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
633     ret = esp_core_dump_do_write_elf_pass(&self);
634     if (ret < 0) return ret;
635     write_len += ret;
636     ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);
637 
638     // Write end, update checksum
639     if (write_cfg->end) {
640         err = write_cfg->end(write_cfg->priv);
641         if (err != ESP_OK) {
642             ESP_COREDUMP_LOGE("Failed to end core dump (%d)!", err);
643             return err;
644         }
645     }
646     return err;
647 }
648 
649 #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
650 
651 /* Below are the helper function to parse the core dump ELF stored in flash */
652 
elf_core_dump_image_mmap(spi_flash_mmap_handle_t * core_data_handle,const void ** map_addr)653 static esp_err_t elf_core_dump_image_mmap(spi_flash_mmap_handle_t* core_data_handle, const void **map_addr)
654 {
655     size_t out_size;
656     assert (core_data_handle);
657     assert(map_addr);
658 
659     /* Find the partition that could potentially contain a (previous) core dump. */
660     const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
661                                                                 ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
662                                                                 NULL);
663     if (!core_part) {
664         ESP_COREDUMP_LOGE("Core dump partition not found!");
665         return ESP_ERR_NOT_FOUND;
666     }
667     if (core_part->size < sizeof(uint32_t)) {
668         ESP_COREDUMP_LOGE("Core dump partition too small!");
669         return ESP_ERR_INVALID_SIZE;
670     }
671     /* Data read from the mmapped core dump partition will be garbage if flash
672      * encryption is enabled in hardware and core dump partition is not encrypted
673      */
674     if (esp_flash_encryption_enabled() && !core_part->encrypted) {
675         ESP_COREDUMP_LOGE("Flash encryption enabled in hardware and core dump partition is not encrypted!");
676         return ESP_ERR_NOT_SUPPORTED;
677     }
678     /* Read the size of the core dump file from the partition */
679     esp_err_t ret = esp_partition_read(core_part, 0, &out_size, sizeof(uint32_t));
680     if (ret != ESP_OK) {
681         ESP_COREDUMP_LOGE("Failed to read core dump data size");
682         return ret;
683     }
684     /* map the full core dump parition, including the checksum. */
685     return esp_partition_mmap(core_part, 0, out_size, SPI_FLASH_MMAP_DATA,
686                               map_addr, core_data_handle);
687 }
688 
elf_parse_version_info(esp_core_dump_summary_t * summary,void * data)689 static void elf_parse_version_info(esp_core_dump_summary_t *summary, void *data)
690 {
691     core_dump_elf_version_info_t *version = (core_dump_elf_version_info_t *)data;
692     summary->core_dump_version = version->version;
693     memcpy(summary->app_elf_sha256, version->app_elf_sha256, ELF_APP_SHA256_SIZE);
694     ESP_COREDUMP_LOGD("Core dump version 0x%x", summary->core_dump_version);
695     ESP_COREDUMP_LOGD("App ELF SHA2 %s", (char *)summary->app_elf_sha256);
696 }
697 
elf_parse_exc_task_name(esp_core_dump_summary_t * summary,void * tcb_data)698 static void elf_parse_exc_task_name(esp_core_dump_summary_t *summary, void *tcb_data)
699 {
700     StaticTask_t *tcb = (StaticTask_t *) tcb_data;
701     /* An ugly way to get the task name. We could possibly use pcTaskGetTaskName here.
702      * But that has assumption that TCB pointer can be used as TaskHandle. So let's
703      * keep it this way. */
704     memset(summary->exc_task, 0, sizeof(summary->exc_task));
705     strlcpy(summary->exc_task, (char *)tcb->ucDummy7, sizeof(summary->exc_task));
706     ESP_COREDUMP_LOGD("Crashing task %s", summary->exc_task);
707 }
708 
esp_core_dump_get_summary(esp_core_dump_summary_t * summary)709 esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
710 {
711     int i;
712     elf_phdr *ph;
713     elf_note *note;
714     const void *map_addr;
715     size_t consumed_note_sz;
716     spi_flash_mmap_handle_t core_data_handle;
717 
718     if (!summary) {
719         return ESP_ERR_INVALID_ARG;
720     }
721     esp_err_t err = elf_core_dump_image_mmap(&core_data_handle, &map_addr);
722     if (err != ESP_OK) {
723         return err;
724     }
725     uint8_t *ptr = (uint8_t *) map_addr + sizeof(core_dump_header_t);
726     elfhdr *eh = (elfhdr *)ptr;
727 
728     ESP_COREDUMP_LOGD("ELF ident %02x %c %c %c", eh->e_ident[0], eh->e_ident[1], eh->e_ident[2], eh->e_ident[3]);
729     ESP_COREDUMP_LOGD("Ph_num %d offset %x", eh->e_phnum, eh->e_phoff);
730 
731     for (i = 0; i < eh->e_phnum; i++) {
732         ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
733         ESP_COREDUMP_LOGD("PHDR type %d off %x vaddr %x paddr %x filesz %x memsz %x flags %x align %x",
734                           ph->p_type, ph->p_offset, ph->p_vaddr, ph->p_paddr, ph->p_filesz, ph->p_memsz,
735                           ph->p_flags, ph->p_align);
736         if (ph->p_type == PT_NOTE) {
737             consumed_note_sz = 0;
738             while(consumed_note_sz < ph->p_memsz) {
739                 note = (elf_note *)(ptr + ph->p_offset + consumed_note_sz);
740                 char *nm = (char *)(ptr + ph->p_offset + consumed_note_sz + sizeof(elf_note));
741                 ESP_COREDUMP_LOGD("Note NameSZ %x DescSZ %x Type %x name %s", note->n_namesz,
742                                   note->n_descsz, note->n_type, nm);
743                 if (strncmp(nm, "EXTRA_INFO", note->n_namesz) == 0 ) {
744                     esp_core_dump_summary_parse_extra_info(summary, (void *)(nm + note->n_namesz));
745                 }
746                 if (strncmp(nm, "ESP_CORE_DUMP_INFO", note->n_namesz) == 0 ) {
747                     elf_parse_version_info(summary, (void *)(nm + note->n_namesz));
748                 }
749                 consumed_note_sz += note->n_namesz + note->n_descsz + sizeof(elf_note);
750                 ALIGN(4, consumed_note_sz);
751             }
752         }
753     }
754     /* Following code assumes that task stack segment follows the TCB segment for the respective task.
755      * In general ELF does not impose any restrictions on segments' order so this can be changed without impacting core dump version.
756      * More universal and flexible way would be to retrieve stack start address from crashed task TCB segment and then look for the stack segment with that address.
757      */
758     int flag = 0;
759     for (i = 0; i < eh->e_phnum; i++) {
760         ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
761         if (ph->p_type == PT_LOAD) {
762             if (flag) {
763                 esp_core_dump_summary_parse_exc_regs(summary, (void *)(ptr + ph->p_offset));
764                 esp_core_dump_summary_parse_backtrace_info(&summary->exc_bt_info, (void *) ph->p_vaddr,
765                                                            (void *)(ptr + ph->p_offset), ph->p_memsz);
766                 break;
767             }
768             if (ph->p_vaddr == summary->exc_tcb) {
769                 elf_parse_exc_task_name(summary, (void *)(ptr + ph->p_offset));
770                 flag = 1;
771             }
772         }
773     }
774     spi_flash_munmap(core_data_handle);
775     return ESP_OK;
776 }
777 
778 #endif // CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
779 
780 #endif //CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
781