/ components / espcoredump / src / core_dump_elf.c
core_dump_elf.c
  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 "sdkconfig.h"
 19  #include "core_dump_elf.h"
 20  
 21  #define ELF_CLASS ELFCLASS32
 22  
 23  #include "elf.h"                    // for ELF file types
 24  
 25  #define ELF_SEG_HEADERS_COUNT(_self_, _task_num_) (uint32_t)((_task_num_) * 2/*stack + tcb*/ \
 26                                      + 1/* regs notes */ + 1/* ver info + extra note */ + ((_self_)->interrupted_task.stack_start ? 1 : 0) \
 27                                      + /* user mapped variables */ esp_core_dump_get_user_ram_segments())
 28  
 29  
 30  #define ELF_HLEN 52
 31  #define ELF_CORE_SEC_TYPE 1
 32  #define ELF_PR_STATUS_SEG_NUM 0
 33  #define ELF_ESP_CORE_DUMP_INFO_TYPE 8266
 34  #define ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE 677
 35  #define ELF_NOTE_NAME_MAX_SIZE 32
 36  #define ELF_APP_SHA256_SIZE 66
 37  
 38  #define ELF_CHECK_ERR(a, ret_val, str, ...) \
 39      if (!(a)) { \
 40          ESP_COREDUMP_LOGE("%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 41          return (ret_val); \
 42      }
 43  
 44  typedef enum
 45  {
 46      ELF_STAGE_CALC_SPACE = 0,
 47      ELF_STAGE_PLACE_HEADERS = 1,
 48      ELF_STAGE_PLACE_DATA = 2
 49  } core_dump_elf_stages_t;
 50  
 51  typedef enum _elf_err_t
 52  {
 53      ELF_PROC_ERR_SKIP_HEADER = 0,
 54      ELF_PROC_ERR_STACK_CORRUPTED = -1,
 55      ELF_PROC_ERR_WRITE_FAIL = -2,
 56      ELF_PROC_ERR_OTHER = -3
 57  } core_dump_elf_proc_err_t;
 58  
 59  typedef struct _core_dump_task_info_t
 60  {
 61      elf_phdr* phdr;
 62      void* frame;
 63      core_dump_task_header_t* task_hdr;
 64      uint32_t task_id;
 65      size_t tcb_sz;
 66      int* size_ptr;
 67  } core_dump_task_data_t;
 68  
 69  typedef struct
 70  {
 71      uint32_t version; // coredump version
 72      uint8_t app_elf_sha256[ELF_APP_SHA256_SIZE]; // sha256 of elf file
 73  } core_dump_elf_version_info_t;
 74  
 75  const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_elf";
 76  
 77  // Main ELF handle type
 78  typedef struct _core_dump_elf_t
 79  {
 80      core_dump_elf_version_info_t    elf_version_info;
 81      uint16_t                        elf_stage;
 82      uint32_t                        elf_next_data_offset;
 83      uint32_t                        bad_tasks_num;
 84      core_dump_task_header_t         interrupted_task;
 85      core_dump_write_config_t *      write_cfg;
 86  } core_dump_elf_t;
 87  
 88  // Represents lightweight implementation to save core dump data into ELF formatted binary
 89  
 90  #define ALIGN(b, var) var = align(b, var)
 91  
 92  #if CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
 93  
 94  static inline uint32_t align(uint32_t width, uint32_t in)
 95  {
 96    return (in + (width - 1)) & -width;
 97  }
 98  
 99  // Builds elf header and check all data offsets
100  static int elf_write_file_header(core_dump_elf_t *self, uint32_t seg_count)
101  {
102      elfhdr elf_hdr; // declare as static to save stack space
103  
104      if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
105          ESP_COREDUMP_LOG_PROCESS("Segment count %u", seg_count);
106          memset(&elf_hdr, 0, sizeof(elfhdr));
107          elf_hdr.e_ident[0] = ELFMAG0;
108          elf_hdr.e_ident[1] = ELFMAG1;
109          elf_hdr.e_ident[2] = ELFMAG2;
110          elf_hdr.e_ident[3] = ELFMAG3;
111          elf_hdr.e_ident[4] = ELFCLASS32;
112          elf_hdr.e_ident[5] = ELFDATA2LSB;
113          elf_hdr.e_ident[6] = EV_CURRENT;
114          elf_hdr.e_ident[7] = ELFOSABI_NONE;
115          elf_hdr.e_ident[8] = 0;
116          elf_hdr.e_type = ET_CORE;
117          elf_hdr.e_machine = esp_core_dump_get_arch_id();
118          elf_hdr.e_flags = 0;
119          elf_hdr.e_version = EV_CURRENT;
120          elf_hdr.e_entry = 0;
121          _Static_assert(sizeof(elfhdr) == ELF_HLEN, "Invalid ELF header struct length!");
122          elf_hdr.e_phoff = sizeof(elfhdr);          // program header table's file offset in bytes.
123          elf_hdr.e_phentsize = sizeof(elf_phdr);    // size in bytes of one entry in the file program header table
124          elf_hdr.e_phnum = seg_count;                 // number of program segments
125          elf_hdr.e_shoff = 0;                       // section header table's file offset in bytes.
126          elf_hdr.e_ehsize = sizeof(elfhdr);         // elf header size
127          elf_hdr.e_shentsize = sizeof(elf_shdr);    // section header's size in bytes.
128          elf_hdr.e_shnum = 0;                       // initial section counter is 0
129          elf_hdr.e_shstrndx = SHN_UNDEF;            // do not use string table
130          // write built elf header into elf image
131          esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)&elf_hdr, sizeof(elf_hdr));
132          ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
133                          "Write ELF header failure (%d)", err);
134          ESP_COREDUMP_LOG_PROCESS("Add file header %u bytes", sizeof(elf_hdr));
135      }
136  
137      return self->elf_stage == ELF_STAGE_PLACE_DATA ? 0 : sizeof(elf_hdr);
138  }
139  
140  static int elf_write_segment_header(core_dump_elf_t *self, elf_phdr* phdr)
141  {
142      ELF_CHECK_ERR(phdr, ELF_PROC_ERR_SKIP_HEADER,
143                      "Header is skipped, stage=(%d).", self->elf_stage);
144  
145      phdr->p_offset = self->elf_next_data_offset;
146      // set segment data information and write it into image
147      esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)phdr, sizeof(elf_phdr));
148      ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
149                      "Write ELF segment header failure (%d)", err);
150      ESP_COREDUMP_LOG_PROCESS("Add segment header %u bytes: type %d, sz %u, off = 0x%x",
151                              sizeof(elf_phdr), phdr->p_type, phdr->p_filesz, phdr->p_offset);
152  
153      return sizeof(elf_phdr);
154  }
155  
156  static int elf_add_segment(core_dump_elf_t *self,
157                              uint32_t type, uint32_t vaddr,
158                              void* data, uint32_t data_sz)
159  {
160      esp_err_t err = ESP_FAIL;
161      elf_phdr seg_hdr = { 0 };
162      int data_len = data_sz;
163  
164      ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
165                  "Invalid data for segment.");
166  
167      ALIGN(4, data_len);
168  
169      if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
170          return data_len + sizeof(elf_phdr);
171      }
172      if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
173          seg_hdr.p_type = type;
174          seg_hdr.p_vaddr = vaddr;
175          seg_hdr.p_paddr = vaddr;
176          seg_hdr.p_filesz = data_len;
177          seg_hdr.p_memsz = data_len;
178          seg_hdr.p_flags = (PF_R | PF_W);
179          int ret = elf_write_segment_header(self, &seg_hdr);
180          ELF_CHECK_ERR((ret > 0), ret,
181                          "Write ELF segment data failure (%d)", ret);
182          self->elf_next_data_offset += data_len;
183          return ret;
184      }
185      ESP_COREDUMP_LOG_PROCESS("Add segment size=%u, start_off=0x%x",
186                                  (uint32_t)data_len, self->elf_next_data_offset);
187      // write segment data only when write function is set and phdr = NULL
188      // write data into segment
189      err = self->write_cfg->write(self->write_cfg->priv, data, (uint32_t)data_len);
190      ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
191                      "Write ELF segment data failure (%d)", err);
192      self->elf_next_data_offset += data_len;
193      return data_len;
194  }
195  
196  static int elf_write_note(core_dump_elf_t *self,
197                              const char* name,
198                              uint32_t type,
199                              void* data,
200                              uint32_t data_sz)
201  {
202      esp_err_t err = ESP_FAIL;
203      // temporary buffer for note name
204      static char name_buffer[ELF_NOTE_NAME_MAX_SIZE] = { 0 };
205      elf_note note_hdr = { 0 };
206      uint32_t name_len = strlen(name) + 1; // get name length including terminator
207      uint32_t data_len = data_sz;
208  
209      ELF_CHECK_ERR(data, ELF_PROC_ERR_OTHER,
210              "Invalid data pointer %x.", (uint32_t)data);
211      ELF_CHECK_ERR((name_len <= ELF_NOTE_NAME_MAX_SIZE), 0,
212                  "Segment note name is too long %d.", name_len);
213  
214      ALIGN(4, data_len);
215      ALIGN(4, name_len);
216      uint32_t note_size = name_len + data_len + sizeof(elf_note);
217      ALIGN(4, note_size);
218  
219      // write segment data during second pass
220      if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
221          memcpy((void*)name_buffer, (void*)name, name_len);
222          note_hdr.n_namesz = name_len;
223          note_hdr.n_descsz = data_sz;
224          note_hdr.n_type = type;
225          // write note header
226          err = self->write_cfg->write(self->write_cfg->priv, (void*)&note_hdr, sizeof(note_hdr));
227          ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
228                  "Write ELF note header failure (%d)", err);
229          // write note name
230          err = self->write_cfg->write(self->write_cfg->priv, (void*)name_buffer, name_len);
231          ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
232                          "Write ELF note name failure (%d)", err);
233          // write note data
234          err = self->write_cfg->write(self->write_cfg->priv, (void*)data, data_len);
235          ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
236                          "Write ELF note data failure (%d)", err);
237          ESP_COREDUMP_LOG_PROCESS("Add note size=%d, start_off=0x%x",
238                                      note_size, self->elf_next_data_offset);
239      }
240      return note_size; // return actual note size
241  }
242  
243  static int elf_add_note(core_dump_elf_t *self,
244                          const char* name,
245                          uint32_t type,
246                          void* data,
247                          uint32_t data_sz)
248  {
249      ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
250              "Invalid data pointer for segment");
251  
252      int note_size = elf_write_note(self, name, type, data, data_sz);
253      ELF_CHECK_ERR((note_size > 0), note_size,
254                      "Write ELF note data failure, returned (%d)", note_size);
255      return note_size; // return actual note segment size
256  }
257  
258  // Append note with registers dump to segment note
259  static int elf_add_regs(core_dump_elf_t *self, core_dump_task_header_t *task)
260  {
261      void *reg_dump;
262  
263      uint32_t len = esp_core_dump_get_task_regs_dump(task, &reg_dump);
264      if (len == 0) {
265          ESP_COREDUMP_LOGE("Zero size register dump for task 0x%x!", task->tcb_addr);
266          return ELF_PROC_ERR_OTHER;
267      }
268  
269      // append note data with dump to existing note
270      return elf_add_note(self,
271                          "CORE",                // note name
272                          ELF_CORE_SEC_TYPE,     // note type for reg dump
273                          reg_dump,      // register dump with pr_status
274                          len);
275  }
276  
277  static int elf_add_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
278  {
279      uint32_t stack_vaddr, stack_len = 0, stack_paddr = 0;
280  
281      ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
282  
283      stack_paddr = esp_core_dump_get_stack(task, &stack_vaddr, &stack_len);
284      ESP_COREDUMP_LOG_PROCESS("Add stack for task 0x%x: addr 0x%x, sz %u",
285                                  task->tcb_addr, stack_vaddr, stack_len);
286      int ret = elf_add_segment(self, PT_LOAD,
287                                  (uint32_t)stack_vaddr,
288                                  (void*)stack_paddr,
289                                  (uint32_t) stack_len);
290      return ret;
291  }
292  
293  static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
294  {
295      ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
296      // add task tcb data into program segment of ELF
297      ESP_COREDUMP_LOG_PROCESS("Add TCB for task 0x%x: addr 0x%x, sz %u",
298                                  task->tcb_addr, task->tcb_addr, COREDUMP_TCB_SIZE);
299      int ret = elf_add_segment(self, PT_LOAD,
300                                  (uint32_t)task->tcb_addr,
301                                  (void*)task->tcb_addr,
302                                  COREDUMP_TCB_SIZE);
303      return ret;
304  }
305  
306  // get index of current crashed task (not always first task in the snapshot)
307  static int elf_get_current_task_index(core_dump_task_header_t** tasks,
308                                          uint32_t task_num)
309  {
310      int task_id;
311      int curr_task_index = COREDUMP_CURR_TASK_NOT_FOUND;
312      void* curr_task_handle = esp_core_dump_get_current_task_handle();
313  
314      // get index of current crashed task (not always first task in the snapshot)
315      for (task_id = 0; task_id < task_num; task_id++) {
316          bool tcb_is_valid = esp_core_dump_tcb_addr_is_sane((uint32_t)tasks[task_id]->tcb_addr);
317          bool stack_is_valid = esp_core_dump_check_stack(tasks[task_id]->stack_start, tasks[task_id]->stack_end);
318          if (stack_is_valid && tcb_is_valid && curr_task_handle == tasks[task_id]->tcb_addr) {
319              curr_task_index = task_id; // save current crashed task index in the snapshot
320              ESP_COREDUMP_LOG_PROCESS("Task #%d, (TCB:%x) is current crashed task.",
321                                          task_id,
322                                          tasks[task_id]->tcb_addr);
323          }
324      }
325      return curr_task_index;
326  }
327  
328  static int elf_process_task_regdump(core_dump_elf_t *self, panic_info_t *info, core_dump_task_header_t *task)
329  {
330      bool task_is_valid = false;
331      bool task_is_current = false;
332  
333      ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
334  
335      if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
336          // Check if task tcb is corrupted (do not update the header, save as is)
337          task_is_valid = esp_core_dump_check_task(info, task, &task_is_current, NULL);
338          if (!task_is_valid) {
339              if (task_is_current) {
340                  ESP_COREDUMP_LOG_PROCESS("Task has incorrect (TCB:%x)!",
341                                              task->tcb_addr);
342              } else {
343                  ESP_COREDUMP_LOG_PROCESS("The current crashed task has broken (TCB:%x)!",
344                                              task->tcb_addr);
345              }
346              self->bad_tasks_num++;
347          }
348      }
349      // extract registers from stack and apply elf data size for stack section
350      return elf_add_regs(self, task);
351  }
352  
353  static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
354  {
355      int ret = ELF_PROC_ERR_OTHER;
356  
357      ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
358  
359      // save tcb of the task as is and apply segment size
360      ret = elf_add_tcb(self, task);
361      if (ret > 0) {
362          ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x) processing completed.",
363                                      task->tcb_addr);
364      } else {
365          ESP_COREDUMP_LOGE("Task (TCB:%x) processing failure = %d",
366                                              task->tcb_addr,
367                                              ret);
368      }
369      return ret;
370  }
371  
372  static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
373  {
374      int ret = ELF_PROC_ERR_OTHER;
375  
376      ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
377  
378      ret = elf_add_stack(self, task);
379      if (ret > 0) {
380          ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), (Stack:%x) stack is processed.",
381                                      task->tcb_addr,
382                                      task->stack_start);
383      } else {
384          ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
385                                      task->tcb_addr,
386                                      task->stack_start,
387                                      ret);
388      }
389      return ret;
390  }
391  
392  static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
393  {
394      int ret;
395      elf_phdr seg_hdr = { 0 };
396  
397      if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
398          // segment header for PR_STATUS notes
399          seg_hdr.p_type = PT_NOTE;
400          seg_hdr.p_vaddr = 0;
401          seg_hdr.p_paddr = 0;
402          seg_hdr.p_filesz = notes_size;
403          seg_hdr.p_memsz = notes_size;
404          seg_hdr.p_flags = (PF_R | PF_W);
405          ret = elf_write_segment_header(self, &seg_hdr);
406          ELF_CHECK_ERR((ret > 0), ret, "NOTE segment header write failure, returned (%d).", ret);
407          self->elf_next_data_offset += notes_size;
408          return sizeof(seg_hdr);
409      } else if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
410          notes_size += sizeof(seg_hdr);
411      } else {
412          // in "Place Data" phase segment body is been already filled by other functions
413          ESP_COREDUMP_LOG_PROCESS("Add NOTE segment, size=%d, start_off=0x%x",
414                                      notes_size, self->elf_next_data_offset);
415          self->elf_next_data_offset += notes_size;
416      }
417      return (int)notes_size;
418  }
419  
420  static int elf_process_tasks_regs(core_dump_elf_t *self, panic_info_t *info,
421                                      core_dump_task_header_t** tasks,
422                                      uint32_t task_num)
423  {
424      int len = 0;
425  
426      uint32_t curr_task_index = elf_get_current_task_index(tasks, task_num);
427      if (curr_task_index == COREDUMP_CURR_TASK_NOT_FOUND) {
428          ESP_COREDUMP_LOG_PROCESS("The current crashed task is broken.");
429          curr_task_index = 0;
430      }
431  
432      // place current task dump first
433      int ret = elf_process_task_regdump(self, info, tasks[curr_task_index]);
434      if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
435          // when writing segments headers this function writes nothing
436          ELF_CHECK_ERR((ret >= 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", curr_task_index, ret);
437      } else {
438          ELF_CHECK_ERR((ret > 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", curr_task_index, ret);
439      }
440      len += ret;
441  
442      // processes PR_STATUS and register dump for each task
443      // each call to the processing function appends PR_STATUS note into note segment
444      // and writes data or updates the segment note header accordingly (if phdr is set)
445      for (int task_id = 0; task_id < task_num; task_id++) {
446          if (task_id == curr_task_index) {
447              continue; // skip current task (already processed)
448          }
449          ret = elf_process_task_regdump(self, info, tasks[task_id]);
450          if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
451              // when writing segments headers this function writes nothing
452              ELF_CHECK_ERR((ret >= 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", task_id, ret);
453          } else {
454              ELF_CHECK_ERR((ret > 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", task_id, ret);
455          }
456          len += ret;
457      }
458      ret = elf_process_note_segment(self, len);
459      ELF_CHECK_ERR((ret > 0), ret,
460                      "PR_STATUS note segment processing failure, returned(%d).", ret);
461  
462      if (esp_core_dump_in_isr_context()) {
463          if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
464              // in this stage we can safely replace task's stack with IRQ's one
465              // if task had corrupted stack it was replaced with fake one in HW dependent code called by elf_process_task_regdump()
466              // in the "write data" stage registers from ISR's stack will be saved in PR_STATUS
467              self->interrupted_task.stack_start = tasks[curr_task_index]->stack_start;
468              self->interrupted_task.stack_end = tasks[curr_task_index]->stack_end;
469              uint32_t isr_stk_end = esp_core_dump_get_isr_stack_end();
470              ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu (%x - %x)", isr_stk_end - (uint32_t)info->frame, (uint32_t)info->frame, isr_stk_end);
471              tasks[curr_task_index]->stack_start = (uint32_t)info->frame;
472              tasks[curr_task_index]->stack_end = isr_stk_end;
473          }
474  
475          // actually we write current task's stack here which was replaced by ISR's
476          len = elf_add_stack(self, &self->interrupted_task);
477          ELF_CHECK_ERR((len > 0), len, "Interrupted task stack write failed, return (%d).", len);
478          ret += len;
479      }
480      return ret;
481  }
482  
483  static int elf_write_tasks_data(core_dump_elf_t *self, panic_info_t *info,
484                                  core_dump_task_header_t** tasks,
485                                  uint32_t task_num)
486  {
487      int elf_len = 0;
488      int task_id;
489      int ret = ELF_PROC_ERR_OTHER;
490  
491      ELF_CHECK_ERR((info && tasks), ELF_PROC_ERR_OTHER, "Invalid input data.");
492  
493      ret = elf_process_tasks_regs(self, info, tasks, task_num);
494      ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
495      elf_len += ret;
496      self->bad_tasks_num = 0; // reset bad task counter
497  
498      // processes all task's stack data and writes segment data into partition
499      // if flash configuration is set
500      for (task_id = 0; task_id < task_num; task_id++) {
501          ret = elf_process_task_tcb(self, tasks[task_id]);
502          ELF_CHECK_ERR((ret > 0), ret,
503                          "Task #%d, TCB write failed, return (%d).", task_id, ret);
504          elf_len += ret;
505          ret = elf_process_task_stack(self, tasks[task_id]);
506          ELF_CHECK_ERR((ret != ELF_PROC_ERR_WRITE_FAIL), ELF_PROC_ERR_WRITE_FAIL,
507                          "Task #%d, stack write failed, return (%d).", task_id, ret);
508          elf_len += ret;
509      }
510      return elf_len;
511  }
512  
513  static int elf_write_core_dump_user_data(core_dump_elf_t *self)
514  {
515      int data_len = 0;
516      int total_sz = 0;
517      uint32_t start = 0;
518  
519      for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
520          data_len = esp_core_dump_get_user_ram_info(i, &start);
521  
522          ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region");
523  
524          if (data_len > 0) {
525              int ret = elf_add_segment(self, PT_LOAD,
526                          (uint32_t)start,
527                          (void*)start,
528                          (uint32_t) data_len);
529  
530              ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret);
531              total_sz += ret;
532          }
533      }
534  
535      return total_sz;
536  }
537  
538  static int elf_write_core_dump_info(core_dump_elf_t *self)
539  {
540      void *extra_info;
541  
542      int data_len = (int)sizeof(self->elf_version_info.app_elf_sha256);
543      data_len = esp_ota_get_app_elf_sha256((char*)self->elf_version_info.app_elf_sha256, (size_t)data_len);
544      ESP_COREDUMP_LOG_PROCESS("Application SHA256='%s', length=%d.",
545                                  self->elf_version_info.app_elf_sha256, data_len);
546      self->elf_version_info.version = COREDUMP_VERSION;
547      int ret = elf_add_note(self,
548                              "ESP_CORE_DUMP_INFO",
549                              ELF_ESP_CORE_DUMP_INFO_TYPE,
550                              &self->elf_version_info,
551                              sizeof(self->elf_version_info));
552      ELF_CHECK_ERR((ret > 0), ret, "Version info note write failed. Returned (%d).", ret);
553      data_len = ret;
554  
555      uint32_t extra_info_len = esp_core_dump_get_extra_info(&extra_info);
556      if (extra_info_len == 0) {
557          ESP_COREDUMP_LOGE("Zero size extra info!");
558          return ELF_PROC_ERR_OTHER;
559      }
560  
561      ret = elf_add_note(self,
562                          "EXTRA_INFO",
563                          ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE,
564                          extra_info,
565                          extra_info_len);
566      ELF_CHECK_ERR((ret > 0), ret, "Extra info note write failed. Returned (%d).", ret);
567      data_len += ret;
568  
569      ret = elf_process_note_segment(self, data_len);
570      ELF_CHECK_ERR((ret > 0), ret,
571                      "EXTRA_INFO note segment processing failure, returned(%d).", ret);
572      return ret;
573  }
574  
575  static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, panic_info_t *info,
576                                              core_dump_task_header_t** tasks,
577                                              uint32_t task_num)
578  {
579      int tot_len = 0;
580  
581      int data_sz = elf_write_file_header(self, ELF_SEG_HEADERS_COUNT(self, task_num));
582      if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
583          ELF_CHECK_ERR((data_sz >= 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
584      } else {
585          ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
586      }
587      tot_len += data_sz;
588      // Calculate whole size include headers for all tasks and main elf header
589      data_sz = elf_write_tasks_data(self, info, tasks, task_num);
590      ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
591      tot_len += data_sz;
592  
593      // write core dump memory regions defined by user
594      data_sz = elf_write_core_dump_user_data(self);
595      ELF_CHECK_ERR((data_sz >= 0), data_sz, "memory regions writing error, returned (%d).", data_sz);
596      tot_len += data_sz;
597  
598      // write data with version control information and some extra info
599      // this should go after tasks processing
600      data_sz = elf_write_core_dump_info(self);
601      ELF_CHECK_ERR((data_sz > 0), data_sz, "Version info writing failed. Returned (%d).", data_sz);
602      tot_len += data_sz;
603  
604      return tot_len;
605  }
606  
607  esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *write_cfg)
608  {
609      esp_err_t err = ESP_OK;
610      static core_dump_task_header_t *tasks[CONFIG_ESP_COREDUMP_MAX_TASKS_NUM];
611      static core_dump_elf_t self;
612      core_dump_header_t dump_hdr;
613      uint32_t tcb_sz = COREDUMP_TCB_SIZE, task_num;
614      int tot_len = sizeof(dump_hdr);
615      int write_len = sizeof(dump_hdr);
616  
617      ELF_CHECK_ERR((info && write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
618  
619      task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP_COREDUMP_MAX_TASKS_NUM);
620      ESP_COREDUMP_LOGI("Found tasks: %d", task_num);
621  
622      self.write_cfg = write_cfg;
623  
624      esp_core_dump_init_extra_info();
625      // On first pass (do not write actual data), but calculate data length needed to allocate memory
626      self.elf_stage = ELF_STAGE_CALC_SPACE;
627      ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
628      int ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
629      if (ret < 0) return ret;
630      tot_len += ret;
631      ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu, tasks processed: %d, broken tasks: %d",
632                                  tot_len, task_num, self.bad_tasks_num);
633      ESP_COREDUMP_LOG_PROCESS("============== Data size = %d bytes ============", tot_len);
634  
635      // Prepare write elf
636      if (write_cfg->prepare) {
637          err = write_cfg->prepare(write_cfg->priv, (uint32_t*)&tot_len);
638          if (err != ESP_OK) {
639              ESP_COREDUMP_LOGE("Failed to prepare core dump storage (%d)!", err);
640              return err;
641          }
642      }
643  
644      // Write start
645      if (write_cfg->start) {
646          err = write_cfg->start(write_cfg->priv);
647          if (err != ESP_OK) {
648              ESP_COREDUMP_LOGE("Failed to start core dump (%d)!", err);
649              return err;
650          }
651      }
652  
653      write_cfg->bad_tasks_num = self.bad_tasks_num;
654  
655      // Write core dump header
656      ALIGN(4, tot_len);
657      ALIGN(4, tcb_sz);
658      dump_hdr.data_len = tot_len;
659      dump_hdr.version = COREDUMP_VERSION;
660      dump_hdr.tasks_num = task_num; // broken tasks are repaired
661      dump_hdr.tcb_sz = tcb_sz;
662      dump_hdr.mem_segs_num = 0;
663      err = write_cfg->write(write_cfg->priv,
664                              (void*)&dump_hdr,
665                              sizeof(core_dump_header_t));
666      if (err != ESP_OK) {
667          ESP_COREDUMP_LOGE("Failed to write core dump header (%d)!", err);
668          return err;
669      }
670  
671      self.elf_stage = ELF_STAGE_PLACE_HEADERS;
672      // set initial offset to elf segments data area
673      self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self, task_num) * sizeof(elf_phdr);
674      ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
675      if (ret < 0) return ret;
676      write_len += ret;
677      ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
678  
679      self.elf_stage = ELF_STAGE_PLACE_DATA;
680      // set initial offset to elf segments data area, this is not necessary in this stage, just for pretty debug output
681      self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self, task_num) * sizeof(elf_phdr);
682      ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
683      if (ret < 0) return ret;
684      write_len += ret;
685      ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);
686  
687      // Get checksum size
688      write_len += esp_core_dump_checksum_finish(write_cfg->priv, NULL);
689      if (write_len != tot_len) {
690          ESP_COREDUMP_LOGD("Write ELF failed (wrong length): %d != %d.", tot_len, write_len);
691      }
692      // Write end, update checksum
693      if (write_cfg->end) {
694          err = write_cfg->end(write_cfg->priv);
695          if (err != ESP_OK) {
696              ESP_COREDUMP_LOGE("Failed to end core dump (%d)!", err);
697              return err;
698          }
699      }
700      return err;
701  }
702  
703  #endif //CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF