core_dump_elf.c 31 KB

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