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*)¬e_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, ®_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