| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780 |
- // Copyright 2015-2019 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 <string.h>
- #include "esp_attr.h"
- #include "esp_partition.h"
- #include "esp_ota_ops.h"
- #include "esp_spi_flash.h"
- #include "esp_flash_encrypt.h"
- #include "sdkconfig.h"
- #include "core_dump_checksum.h"
- #include "core_dump_elf.h"
- #include "esp_core_dump_port.h"
- #include "esp_core_dump_port_impl.h"
- #include "esp_core_dump_common.h"
- #define ELF_CLASS ELFCLASS32
- #include "elf.h" // for ELF file types
- #define ELF_SEG_HEADERS_COUNT(_self_) ((_self_)->segs_count)
- #define ELF_HLEN 52
- #define ELF_CORE_SEC_TYPE 1
- #define ELF_PR_STATUS_SEG_NUM 0
- #define ELF_ESP_CORE_DUMP_INFO_TYPE 8266
- #define ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE 677
- #define ELF_NOTE_NAME_MAX_SIZE 32
- #define ELF_APP_SHA256_SIZE 66
- #define ELF_CHECK_ERR(a, ret_val, str, ...) \
- if (!(a)) { \
- ESP_COREDUMP_LOGE("%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
- return (ret_val); \
- }
- typedef enum
- {
- ELF_STAGE_CALC_SPACE = 0,
- ELF_STAGE_PLACE_HEADERS = 1,
- ELF_STAGE_PLACE_DATA = 2
- } core_dump_elf_stages_t;
- typedef enum _elf_err_t
- {
- ELF_PROC_ERR_SKIP_HEADER = 0,
- ELF_PROC_ERR_STACK_CORRUPTED = -1,
- ELF_PROC_ERR_WRITE_FAIL = -2,
- ELF_PROC_ERR_OTHER = -3
- } core_dump_elf_proc_err_t;
- typedef struct _core_dump_task_info_t
- {
- elf_phdr* phdr;
- void* frame;
- core_dump_task_header_t* task_hdr;
- uint32_t task_id;
- size_t tcb_sz;
- int* size_ptr;
- } core_dump_task_data_t;
- typedef struct
- {
- uint32_t version; // coredump version
- uint8_t app_elf_sha256[ELF_APP_SHA256_SIZE]; // sha256 of elf file
- } core_dump_elf_version_info_t;
- const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_elf";
- // Main ELF handle type
- typedef struct _core_dump_elf_t
- {
- core_dump_elf_version_info_t elf_version_info;
- uint16_t elf_stage;
- uint32_t elf_next_data_offset;
- uint16_t segs_count;
- core_dump_write_config_t * write_cfg;
- } core_dump_elf_t;
- // Represents lightweight implementation to save core dump data into ELF formatted binary
- #define ALIGN(b, var) var = align(b, var)
- #if CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
- static inline uint32_t align(uint32_t width, uint32_t in)
- {
- return (in + (width - 1)) & -width;
- }
- // Builds elf header and check all data offsets
- static int elf_write_file_header(core_dump_elf_t *self, uint32_t seg_count)
- {
- elfhdr elf_hdr; // declare as static to save stack space
- if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
- ESP_COREDUMP_LOG_PROCESS("Segment count %u", seg_count);
- memset(&elf_hdr, 0, sizeof(elfhdr));
- elf_hdr.e_ident[0] = ELFMAG0;
- elf_hdr.e_ident[1] = ELFMAG1;
- elf_hdr.e_ident[2] = ELFMAG2;
- elf_hdr.e_ident[3] = ELFMAG3;
- elf_hdr.e_ident[4] = ELFCLASS32;
- elf_hdr.e_ident[5] = ELFDATA2LSB;
- elf_hdr.e_ident[6] = EV_CURRENT;
- elf_hdr.e_ident[7] = ELFOSABI_NONE;
- elf_hdr.e_ident[8] = 0;
- elf_hdr.e_type = ET_CORE;
- elf_hdr.e_machine = esp_core_dump_get_arch_id();
- elf_hdr.e_flags = 0;
- elf_hdr.e_version = EV_CURRENT;
- elf_hdr.e_entry = 0;
- _Static_assert(sizeof(elfhdr) == ELF_HLEN, "Invalid ELF header struct length!");
- elf_hdr.e_phoff = sizeof(elfhdr); // program header table's file offset in bytes.
- elf_hdr.e_phentsize = sizeof(elf_phdr); // size in bytes of one entry in the file program header table
- elf_hdr.e_phnum = seg_count; // number of program segments
- elf_hdr.e_shoff = 0; // section header table's file offset in bytes.
- elf_hdr.e_ehsize = sizeof(elfhdr); // elf header size
- elf_hdr.e_shentsize = sizeof(elf_shdr); // section header's size in bytes.
- elf_hdr.e_shnum = 0; // initial section counter is 0
- elf_hdr.e_shstrndx = SHN_UNDEF; // do not use string table
- // write built elf header into elf image
- esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)&elf_hdr, sizeof(elf_hdr));
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF header failure (%d)", err);
- ESP_COREDUMP_LOG_PROCESS("Add file header %u bytes", sizeof(elf_hdr));
- }
- return self->elf_stage == ELF_STAGE_PLACE_DATA ? 0 : sizeof(elf_hdr);
- }
- static int elf_write_segment_header(core_dump_elf_t *self, elf_phdr* phdr)
- {
- ELF_CHECK_ERR(phdr, ELF_PROC_ERR_SKIP_HEADER,
- "Header is skipped, stage=(%d).", self->elf_stage);
- phdr->p_offset = self->elf_next_data_offset;
- // set segment data information and write it into image
- esp_err_t err = self->write_cfg->write(self->write_cfg->priv, (void*)phdr, sizeof(elf_phdr));
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF segment header failure (%d)", err);
- ESP_COREDUMP_LOG_PROCESS("Add segment header %u bytes: type %d, sz %u, off = 0x%x",
- sizeof(elf_phdr), phdr->p_type, phdr->p_filesz, phdr->p_offset);
- return sizeof(elf_phdr);
- }
- static int elf_add_segment(core_dump_elf_t *self,
- uint32_t type, uint32_t vaddr,
- void* data, uint32_t data_sz)
- {
- esp_err_t err = ESP_FAIL;
- elf_phdr seg_hdr = { 0 };
- int data_len = data_sz;
- ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
- "Invalid data for segment.");
- ALIGN(4, data_len);
- if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
- self->segs_count++;
- return data_len + sizeof(elf_phdr);
- }
- if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
- seg_hdr.p_type = type;
- seg_hdr.p_vaddr = vaddr;
- seg_hdr.p_paddr = vaddr;
- seg_hdr.p_filesz = data_len;
- seg_hdr.p_memsz = data_len;
- seg_hdr.p_flags = (PF_R | PF_W);
- int ret = elf_write_segment_header(self, &seg_hdr);
- ELF_CHECK_ERR((ret > 0), ret,
- "Write ELF segment data failure (%d)", ret);
- self->elf_next_data_offset += data_len;
- return ret;
- }
- ESP_COREDUMP_LOG_PROCESS("Add segment size=%u, start_off=0x%x",
- (uint32_t)data_len, self->elf_next_data_offset);
- // write segment data only when write function is set and phdr = NULL
- // write data into segment
- err = self->write_cfg->write(self->write_cfg->priv, data, (uint32_t)data_len);
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF segment data failure (%d)", err);
- self->elf_next_data_offset += data_len;
- return data_len;
- }
- static int elf_write_note(core_dump_elf_t *self,
- const char* name,
- uint32_t type,
- void* data,
- uint32_t data_sz)
- {
- esp_err_t err = ESP_FAIL;
- // temporary buffer for note name
- static char name_buffer[ELF_NOTE_NAME_MAX_SIZE] = { 0 };
- elf_note note_hdr = { 0 };
- uint32_t name_len = strlen(name) + 1; // get name length including terminator
- uint32_t data_len = data_sz;
- ELF_CHECK_ERR(data, ELF_PROC_ERR_OTHER,
- "Invalid data pointer %x.", (uint32_t)data);
- ELF_CHECK_ERR((name_len <= ELF_NOTE_NAME_MAX_SIZE), 0,
- "Segment note name is too long %d.", name_len);
- ALIGN(4, data_len);
- ALIGN(4, name_len);
- uint32_t note_size = name_len + data_len + sizeof(elf_note);
- ALIGN(4, note_size);
- // write segment data during second pass
- if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
- memcpy((void*)name_buffer, (void*)name, name_len);
- note_hdr.n_namesz = name_len;
- note_hdr.n_descsz = data_sz;
- note_hdr.n_type = type;
- // write note header
- err = self->write_cfg->write(self->write_cfg->priv, (void*)¬e_hdr, sizeof(note_hdr));
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF note header failure (%d)", err);
- // write note name
- err = self->write_cfg->write(self->write_cfg->priv, (void*)name_buffer, name_len);
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF note name failure (%d)", err);
- // write note data
- err = self->write_cfg->write(self->write_cfg->priv, (void*)data, data_len);
- ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL,
- "Write ELF note data failure (%d)", err);
- ESP_COREDUMP_LOG_PROCESS("Add note size=%d, start_off=0x%x",
- note_size, self->elf_next_data_offset);
- }
- return note_size; // return actual note size
- }
- static int elf_add_note(core_dump_elf_t *self,
- const char* name,
- uint32_t type,
- void* data,
- uint32_t data_sz)
- {
- ELF_CHECK_ERR((data != NULL), ELF_PROC_ERR_OTHER,
- "Invalid data pointer for segment");
- int note_size = elf_write_note(self, name, type, data, data_sz);
- ELF_CHECK_ERR((note_size > 0), note_size,
- "Write ELF note data failure, returned (%d)", note_size);
- return note_size; // return actual note segment size
- }
- // Append note with registers dump to segment note
- static int elf_add_regs(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- void *reg_dump;
- uint32_t len = esp_core_dump_get_task_regs_dump(task, ®_dump);
- if (len == 0) {
- ESP_COREDUMP_LOGE("Zero size register dump for task 0x%x!", task->tcb_addr);
- return ELF_PROC_ERR_OTHER;
- }
- // append note data with dump to existing note
- return elf_add_note(self,
- "CORE", // note name
- ELF_CORE_SEC_TYPE, // note type for reg dump
- reg_dump, // register dump with pr_status
- len);
- }
- static int elf_add_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- uint32_t stack_vaddr, stack_len = 0, stack_paddr = 0;
- ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
- stack_len = esp_core_dump_get_stack(task, &stack_vaddr, &stack_paddr);
- ESP_COREDUMP_LOG_PROCESS("Add stack for task 0x%x: addr 0x%x, sz %u",
- task->tcb_addr, stack_vaddr, stack_len);
- int ret = elf_add_segment(self, PT_LOAD,
- (uint32_t)stack_vaddr,
- (void*)stack_paddr,
- (uint32_t) stack_len);
- return ret;
- }
- static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
- // add task tcb data into program segment of ELF
- ESP_COREDUMP_LOG_PROCESS("Add TCB for task 0x%x: addr 0x%x, sz %u",
- task->tcb_addr, task->tcb_addr,
- esp_core_dump_get_tcb_len());
- int ret = elf_add_segment(self, PT_LOAD,
- (uint32_t)task->tcb_addr,
- task->tcb_addr,
- esp_core_dump_get_tcb_len());
- return ret;
- }
- static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- int ret = ELF_PROC_ERR_OTHER;
- ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
- // save tcb of the task as is and apply segment size
- ret = elf_add_tcb(self, task);
- if (ret <= 0) {
- ESP_COREDUMP_LOGE("Task (TCB:%x) processing failure = %d",
- task->tcb_addr,
- ret);
- }
- return ret;
- }
- static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- int ret = ELF_PROC_ERR_OTHER;
- ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
- ret = elf_add_stack(self, task);
- if (ret <= 0) {
- ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
- task->tcb_addr,
- task->stack_start,
- ret);
- }
- return ret;
- }
- static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
- {
- int ret;
- elf_phdr seg_hdr = { 0 };
- if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
- // segment header for PR_STATUS notes
- seg_hdr.p_type = PT_NOTE;
- seg_hdr.p_vaddr = 0;
- seg_hdr.p_paddr = 0;
- seg_hdr.p_filesz = notes_size;
- seg_hdr.p_memsz = notes_size;
- seg_hdr.p_flags = (PF_R | PF_W);
- ret = elf_write_segment_header(self, &seg_hdr);
- ELF_CHECK_ERR((ret > 0), ret, "NOTE segment header write failure, returned (%d).", ret);
- self->elf_next_data_offset += notes_size;
- return sizeof(seg_hdr);
- } else if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
- self->segs_count++;
- notes_size += sizeof(seg_hdr);
- } else {
- // in "Place Data" phase segment body is been already filled by other functions
- ESP_COREDUMP_LOG_PROCESS("Add NOTE segment, size=%d, start_off=0x%x",
- notes_size, self->elf_next_data_offset);
- self->elf_next_data_offset += notes_size;
- }
- return (int)notes_size;
- }
- static int elf_process_tasks_regs(core_dump_elf_t *self)
- {
- core_dump_task_header_t task_hdr = { 0 };
- void *task = NULL;
- int len = 0;
- int ret = 0;
- esp_core_dump_reset_tasks_snapshots_iter();
- task = esp_core_dump_get_current_task_handle();
- if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
- // place current task dump first
- ret = elf_add_regs(self, &task_hdr);
- if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
- // when writing segments headers this function writes nothing
- ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
- } else {
- ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
- }
- len += ret;
- }
- // processes PR_STATUS and register dump for each task
- // each call to the processing function appends PR_STATUS note into note segment
- // and writes data or updates the segment note header accordingly (if phdr is set)
- task = NULL;
- while ((task = esp_core_dump_get_next_task(task))) {
- if (task == esp_core_dump_get_current_task_handle()) {
- continue; // skip current task (already processed)
- }
- if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
- ret = elf_add_regs(self, &task_hdr);
- if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
- // when writing segments headers this function writes nothing
- ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
- } else {
- ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
- }
- len += ret;
- }
- }
- ret = elf_process_note_segment(self, len); // tasks regs note
- ELF_CHECK_ERR((ret > 0), ret,
- "PR_STATUS note segment processing failure, returned(%d).", ret);
- return ret;
- }
- static int elf_save_task(core_dump_elf_t *self, core_dump_task_header_t *task)
- {
- int elf_len = 0;
- int ret = elf_process_task_tcb(self, task);
- ELF_CHECK_ERR((ret > 0), ret,
- "Task %x, TCB write failed, return (%d).", task->tcb_addr, ret);
- elf_len += ret;
- ret = elf_process_task_stack(self, task);
- ELF_CHECK_ERR((ret != ELF_PROC_ERR_WRITE_FAIL), ELF_PROC_ERR_WRITE_FAIL,
- "Task %x, stack write failed, return (%d).", task->tcb_addr, ret);
- elf_len += ret;
- return elf_len;
- }
- static int elf_write_tasks_data(core_dump_elf_t *self)
- {
- int elf_len = 0;
- void *task = NULL;
- core_dump_task_header_t task_hdr = { 0 };
- core_dump_mem_seg_header_t interrupted_stack = { 0 };
- int ret = ELF_PROC_ERR_OTHER;
- uint16_t tasks_num = 0;
- uint16_t bad_tasks_num = 0;
- ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================");
- ret = elf_process_tasks_regs(self);
- ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
- elf_len += ret;
- ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================");
- // processes all task's stack data and writes segment data into partition
- // if flash configuration is set
- task = NULL;
- esp_core_dump_reset_tasks_snapshots_iter();
- while ((task = esp_core_dump_get_next_task(task))) {
- tasks_num++;
- if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &interrupted_stack)) {
- bad_tasks_num++;
- continue;
- }
- ret = elf_save_task(self, &task_hdr);
- ELF_CHECK_ERR((ret > 0), ret,
- "Task %x, TCB write failed, return (%d).", task, ret);
- elf_len += ret;
- if (interrupted_stack.size > 0) {
- ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x",
- interrupted_stack.size, interrupted_stack.start);
- ret = elf_add_segment(self, PT_LOAD,
- (uint32_t)interrupted_stack.start,
- (void*)interrupted_stack.start,
- (uint32_t)interrupted_stack.size);
- ELF_CHECK_ERR((ret > 0), ret, "Interrupted task stack write failed, return (%d).", ret);
- elf_len += ret;
- }
- }
- ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num);
- return elf_len;
- }
- static int elf_write_core_dump_user_data(core_dump_elf_t *self)
- {
- int data_len = 0;
- int total_sz = 0;
- uint32_t start = 0;
- for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
- data_len = esp_core_dump_get_user_ram_info(i, &start);
- ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region");
- if (data_len > 0) {
- int ret = elf_add_segment(self, PT_LOAD,
- (uint32_t)start,
- (void*)start,
- (uint32_t) data_len);
- ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret);
- total_sz += ret;
- }
- }
- return total_sz;
- }
- static int elf_write_core_dump_info(core_dump_elf_t *self)
- {
- void *extra_info = NULL;
- ESP_COREDUMP_LOG_PROCESS("================ Processing coredump info ================");
- int data_len = (int)sizeof(self->elf_version_info.app_elf_sha256);
- data_len = esp_ota_get_app_elf_sha256((char*)self->elf_version_info.app_elf_sha256, (size_t)data_len);
- ESP_COREDUMP_LOG_PROCESS("Application SHA256='%s', length=%d.",
- self->elf_version_info.app_elf_sha256, data_len);
- self->elf_version_info.version = esp_core_dump_elf_version();
- int ret = elf_add_note(self,
- "ESP_CORE_DUMP_INFO",
- ELF_ESP_CORE_DUMP_INFO_TYPE,
- &self->elf_version_info,
- sizeof(self->elf_version_info));
- ELF_CHECK_ERR((ret > 0), ret, "Version info note write failed. Returned (%d).", ret);
- data_len = ret;
- uint32_t extra_info_len = esp_core_dump_get_extra_info(&extra_info);
- if (extra_info_len == 0) {
- ESP_COREDUMP_LOGE("Zero size extra info!");
- return ELF_PROC_ERR_OTHER;
- }
- ret = elf_add_note(self,
- "EXTRA_INFO",
- ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE,
- extra_info,
- extra_info_len);
- ELF_CHECK_ERR((ret > 0), ret, "Extra info note write failed. Returned (%d).", ret);
- data_len += ret;
- ret = elf_process_note_segment(self, data_len);
- ELF_CHECK_ERR((ret > 0), ret,
- "EXTRA_INFO note segment processing failure, returned(%d).", ret);
- return ret;
- }
- static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self)
- {
- int tot_len = 0;
- int data_sz = elf_write_file_header(self, ELF_SEG_HEADERS_COUNT(self));
- if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
- ELF_CHECK_ERR((data_sz >= 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
- } else {
- ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
- }
- tot_len += data_sz;
- // Calculate whole size include headers for all tasks and main elf header
- data_sz = elf_write_tasks_data(self);
- ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
- tot_len += data_sz;
- // write core dump memory regions defined by user
- data_sz = elf_write_core_dump_user_data(self);
- ELF_CHECK_ERR((data_sz >= 0), data_sz, "memory regions writing error, returned (%d).", data_sz);
- tot_len += data_sz;
- // write data with version control information and some extra info
- // this should go after tasks processing
- data_sz = elf_write_core_dump_info(self);
- ELF_CHECK_ERR((data_sz > 0), data_sz, "Version info writing failed. Returned (%d).", data_sz);
- tot_len += data_sz;
- return tot_len;
- }
- esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg)
- {
- static core_dump_elf_t self = { 0 };
- static core_dump_header_t dump_hdr = { 0 };
- esp_err_t err = ESP_OK;
- int tot_len = sizeof(dump_hdr);
- int write_len = sizeof(dump_hdr);
- ELF_CHECK_ERR((write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
- self.write_cfg = write_cfg;
- // On first pass (do not write actual data), but calculate data length needed to allocate memory
- self.elf_stage = ELF_STAGE_CALC_SPACE;
- ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
- int ret = esp_core_dump_do_write_elf_pass(&self);
- if (ret < 0) return ret;
- tot_len += ret;
- ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu", tot_len);
- ESP_COREDUMP_LOG_PROCESS("============== Data size = %d bytes ============", tot_len);
- // Prepare write elf
- if (write_cfg->prepare) {
- err = write_cfg->prepare(write_cfg->priv, (uint32_t*)&tot_len);
- if (err != ESP_OK) {
- ESP_COREDUMP_LOGE("Failed to prepare core dump storage (%d)!", err);
- return err;
- }
- }
- // Write start
- if (write_cfg->start) {
- err = write_cfg->start(write_cfg->priv);
- if (err != ESP_OK) {
- ESP_COREDUMP_LOGE("Failed to start core dump (%d)!", err);
- return err;
- }
- }
- // Write core dump header
- dump_hdr.data_len = tot_len;
- dump_hdr.version = esp_core_dump_elf_version();
- dump_hdr.tasks_num = 0; // unused in ELF format
- dump_hdr.tcb_sz = 0; // unused in ELF format
- dump_hdr.mem_segs_num = 0; // unused in ELF format
- err = write_cfg->write(write_cfg->priv,
- (void*)&dump_hdr,
- sizeof(core_dump_header_t));
- if (err != ESP_OK) {
- ESP_COREDUMP_LOGE("Failed to write core dump header (%d)!", err);
- return err;
- }
- self.elf_stage = ELF_STAGE_PLACE_HEADERS;
- // set initial offset to elf segments data area
- self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
- ret = esp_core_dump_do_write_elf_pass(&self);
- if (ret < 0) return ret;
- write_len += ret;
- ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
- self.elf_stage = ELF_STAGE_PLACE_DATA;
- // set initial offset to elf segments data area, this is not necessary in this stage, just for pretty debug output
- self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
- ret = esp_core_dump_do_write_elf_pass(&self);
- if (ret < 0) return ret;
- write_len += ret;
- ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);
- // Write end, update checksum
- if (write_cfg->end) {
- err = write_cfg->end(write_cfg->priv);
- if (err != ESP_OK) {
- ESP_COREDUMP_LOGE("Failed to end core dump (%d)!", err);
- return err;
- }
- }
- return err;
- }
- #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
- /* Below are the helper function to parse the core dump ELF stored in flash */
- static esp_err_t elf_core_dump_image_mmap(spi_flash_mmap_handle_t* core_data_handle, const void **map_addr)
- {
- size_t out_size;
- assert (core_data_handle);
- assert(map_addr);
- /* Find the partition that could potentially contain a (previous) core dump. */
- const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
- ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
- NULL);
- if (!core_part) {
- ESP_COREDUMP_LOGE("Core dump partition not found!");
- return ESP_ERR_NOT_FOUND;
- }
- if (core_part->size < sizeof(uint32_t)) {
- ESP_COREDUMP_LOGE("Core dump partition too small!");
- return ESP_ERR_INVALID_SIZE;
- }
- /* Data read from the mmapped core dump partition will be garbage if flash
- * encryption is enabled in hardware and core dump partition is not encrypted
- */
- if (esp_flash_encryption_enabled() && !core_part->encrypted) {
- ESP_COREDUMP_LOGE("Flash encryption enabled in hardware and core dump partition is not encrypted!");
- return ESP_ERR_NOT_SUPPORTED;
- }
- /* Read the size of the core dump file from the partition */
- esp_err_t ret = esp_partition_read(core_part, 0, &out_size, sizeof(uint32_t));
- if (ret != ESP_OK) {
- ESP_COREDUMP_LOGE("Failed to read core dump data size");
- return ret;
- }
- /* map the full core dump parition, including the checksum. */
- return esp_partition_mmap(core_part, 0, out_size, SPI_FLASH_MMAP_DATA,
- map_addr, core_data_handle);
- }
- static void elf_parse_version_info(esp_core_dump_summary_t *summary, void *data)
- {
- core_dump_elf_version_info_t *version = (core_dump_elf_version_info_t *)data;
- summary->core_dump_version = version->version;
- memcpy(summary->app_elf_sha256, version->app_elf_sha256, ELF_APP_SHA256_SIZE);
- ESP_COREDUMP_LOGD("Core dump version 0x%x", summary->core_dump_version);
- ESP_COREDUMP_LOGD("App ELF SHA2 %s", (char *)summary->app_elf_sha256);
- }
- static void elf_parse_exc_task_name(esp_core_dump_summary_t *summary, void *tcb_data)
- {
- StaticTask_t *tcb = (StaticTask_t *) tcb_data;
- /* An ugly way to get the task name. We could possibly use pcTaskGetTaskName here.
- * But that has assumption that TCB pointer can be used as TaskHandle. So let's
- * keep it this way. */
- memset(summary->exc_task, 0, sizeof(summary->exc_task));
- strlcpy(summary->exc_task, (char *)tcb->ucDummy7, sizeof(summary->exc_task));
- ESP_COREDUMP_LOGD("Crashing task %s", summary->exc_task);
- }
- esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
- {
- int i;
- elf_phdr *ph;
- elf_note *note;
- const void *map_addr;
- size_t consumed_note_sz;
- spi_flash_mmap_handle_t core_data_handle;
- if (!summary) {
- return ESP_ERR_INVALID_ARG;
- }
- esp_err_t err = elf_core_dump_image_mmap(&core_data_handle, &map_addr);
- if (err != ESP_OK) {
- return err;
- }
- uint8_t *ptr = (uint8_t *) map_addr + sizeof(core_dump_header_t);
- elfhdr *eh = (elfhdr *)ptr;
- 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]);
- ESP_COREDUMP_LOGD("Ph_num %d offset %x", eh->e_phnum, eh->e_phoff);
- for (i = 0; i < eh->e_phnum; i++) {
- ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
- ESP_COREDUMP_LOGD("PHDR type %d off %x vaddr %x paddr %x filesz %x memsz %x flags %x align %x",
- ph->p_type, ph->p_offset, ph->p_vaddr, ph->p_paddr, ph->p_filesz, ph->p_memsz,
- ph->p_flags, ph->p_align);
- if (ph->p_type == PT_NOTE) {
- consumed_note_sz = 0;
- while(consumed_note_sz < ph->p_memsz) {
- note = (elf_note *)(ptr + ph->p_offset + consumed_note_sz);
- char *nm = (char *)(ptr + ph->p_offset + consumed_note_sz + sizeof(elf_note));
- ESP_COREDUMP_LOGD("Note NameSZ %x DescSZ %x Type %x name %s", note->n_namesz,
- note->n_descsz, note->n_type, nm);
- if (strncmp(nm, "EXTRA_INFO", note->n_namesz) == 0 ) {
- esp_core_dump_summary_parse_extra_info(summary, (void *)(nm + note->n_namesz));
- }
- if (strncmp(nm, "ESP_CORE_DUMP_INFO", note->n_namesz) == 0 ) {
- elf_parse_version_info(summary, (void *)(nm + note->n_namesz));
- }
- consumed_note_sz += note->n_namesz + note->n_descsz + sizeof(elf_note);
- ALIGN(4, consumed_note_sz);
- }
- }
- }
- /* Following code assumes that task stack segment follows the TCB segment for the respective task.
- * In general ELF does not impose any restrictions on segments' order so this can be changed without impacting core dump version.
- * 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.
- */
- int flag = 0;
- for (i = 0; i < eh->e_phnum; i++) {
- ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
- if (ph->p_type == PT_LOAD) {
- if (flag) {
- esp_core_dump_summary_parse_exc_regs(summary, (void *)(ptr + ph->p_offset));
- esp_core_dump_summary_parse_backtrace_info(&summary->exc_bt_info, (void *) ph->p_vaddr,
- (void *)(ptr + ph->p_offset), ph->p_memsz);
- break;
- }
- if (ph->p_vaddr == summary->exc_tcb) {
- elf_parse_exc_task_name(summary, (void *)(ptr + ph->p_offset));
- flag = 1;
- }
- }
- }
- spi_flash_munmap(core_data_handle);
- return ESP_OK;
- }
- #endif // CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
- #endif //CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
|