You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

coredump.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * Copyright (c) 2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-08-16 Rbb666 first version
  9. */
  10. #include <string.h>
  11. #include "coredump.h"
  12. #include "mcd_elf_define.h"
  13. #include "arm\mcd_arm_define.h"
  14. typedef uint16_t elf_half;
  15. typedef uint32_t elf_word;
  16. #if MCOREDUMP_ELF_CLASS == ELFCLASS32
  17. typedef uint32_t elf_addr;
  18. typedef uint32_t elf_off;
  19. typedef struct elf32_phdr elf_phdr_t;
  20. #else
  21. typedef uint64_t elf_addr;
  22. typedef uint64_t elf_off;
  23. typedef struct elf64_phdr elf_phdr_t;
  24. #endif
  25. /* Elf file header type */
  26. typedef struct
  27. {
  28. unsigned char e_ident[EI_NIDENT];
  29. elf_half e_type;
  30. elf_half e_machine;
  31. elf_word e_version;
  32. elf_addr e_entry;
  33. elf_off e_phoff;
  34. elf_off e_shoff;
  35. elf_word e_flags;
  36. elf_half e_ehsize;
  37. elf_half e_phentsize;
  38. elf_half e_phnum;
  39. elf_half e_shentsize;
  40. elf_half e_shnum;
  41. elf_half e_shstrndx;
  42. } elf_ehdr_t;
  43. /* Segment header type for 32bit arch */
  44. struct elf32_phdr
  45. {
  46. elf_word p_type;
  47. elf_off p_offset;
  48. elf_addr p_vaddr;
  49. elf_addr p_paddr;
  50. elf_off p_filesz;
  51. elf_off p_memsz;
  52. elf_word p_flags;
  53. elf_off p_align;
  54. };
  55. /* Segment header type for 64bit arch */
  56. struct elf64_phdr
  57. {
  58. elf_word p_type; /* Identifies program segment type */
  59. elf_word p_flags; /* Segment flags */
  60. elf_off p_offset; /* Segment file offset */
  61. elf_addr p_vaddr; /* Segment virtual address */
  62. elf_addr p_paddr; /* Segment physical address */
  63. elf_off p_filesz; /* Segment size in file */
  64. elf_off p_memsz; /* Segment size in memory */
  65. elf_off p_align; /* Segment alignment, file & memory */
  66. };
  67. typedef struct
  68. {
  69. elf_word namesz; /* Size of entry's owner string */
  70. elf_word descsz; /* Size of the note descriptor */
  71. elf_word type; /* Interpretation of the descriptor */
  72. char name[1];
  73. } elf_note_base_t;
  74. typedef struct
  75. {
  76. elf_word namesz; /* Size of entry's owner string */
  77. elf_word descsz; /* Size of the note descriptor */
  78. elf_word type; /* Interpretation of the descriptor */
  79. char name[MCD_ALIGN(sizeof("CORE"), 4)]; /* The only support name is "CORE" */
  80. uint8_t desc[MCOREDUMP_PRSTATUS_SIZE]; /* descriptor of this note entry type */
  81. } elf_note_prstatus_t;
  82. typedef struct
  83. {
  84. elf_word namesz; /* Size of entry's owner string */
  85. elf_word descsz; /* Size of the note descriptor */
  86. elf_word type; /* Interpretation of the descriptor */
  87. char name[MCD_ALIGN(sizeof("LINUX"), 4)]; /* The only support name is "LINUX" */
  88. uint8_t desc[MCOREDUMP_FPREGSET_SIZE]; /* descriptor of this note entry type */
  89. } elf_note_fpreg_entry_t;
  90. typedef struct
  91. {
  92. elf_off file_off;
  93. uint32_t with_fp;
  94. uint32_t stack_size;
  95. mcd_writeout_func_t writeout_func;
  96. union
  97. {
  98. elf_ehdr_t elf_header;
  99. elf_phdr_t program_header;
  100. elf_note_prstatus_t prstatus;
  101. elf_note_fpreg_entry_t note_fp;
  102. } tmp;
  103. core_regset_type tmp_core_rset;
  104. fp_regset_type tmp_fp_rset;
  105. } mcd_instance_t;
  106. static core_regset_type current_core_regset;
  107. static fp_regset_type current_fp_regset;
  108. static mcd_instance_t m_ctx;
  109. static void fill_core_file_header(elf_ehdr_t *elf_header, uint16_t num)
  110. {
  111. memset(elf_header, 0, sizeof(elf_ehdr_t));
  112. elf_header->e_ident[EI_MAG0] = ELFMAG0;
  113. elf_header->e_ident[EI_MAG1] = ELFMAG1;
  114. elf_header->e_ident[EI_MAG2] = ELFMAG2;
  115. elf_header->e_ident[EI_MAG3] = ELFMAG3;
  116. elf_header->e_ident[EI_CLASS] = MCOREDUMP_ELF_CLASS;
  117. elf_header->e_ident[EI_DATA] = MCOREDUMP_ELF_ENDIAN;
  118. elf_header->e_ident[EI_VERSION] = 1;
  119. elf_header->e_ident[EI_OSABI] = MCOREDUMP_OSABI;
  120. elf_header->e_type = ET_CORE;
  121. elf_header->e_machine = MCOREDUMP_MACHINE;
  122. elf_header->e_version = 1;
  123. elf_header->e_entry = 0;
  124. elf_header->e_phoff = sizeof(elf_ehdr_t);
  125. elf_header->e_shoff = 0;
  126. elf_header->e_flags = 0;
  127. elf_header->e_ehsize = sizeof(elf_ehdr_t);
  128. elf_header->e_phentsize = sizeof(elf_phdr_t);
  129. elf_header->e_phnum = num;
  130. elf_header->e_shentsize = 0;
  131. elf_header->e_shnum = 0;
  132. elf_header->e_shstrndx = 0;
  133. }
  134. static void fill_program_header(elf_phdr_t *program_header, elf_word type,
  135. elf_addr vaddr, elf_off filesz, elf_off memsz,
  136. elf_word flag)
  137. {
  138. program_header->p_type = type;
  139. program_header->p_offset = m_ctx.file_off;
  140. program_header->p_vaddr = vaddr;
  141. program_header->p_paddr = 0;
  142. program_header->p_filesz = filesz;
  143. program_header->p_memsz = memsz;
  144. program_header->p_flags = flag;
  145. program_header->p_align = 1;
  146. m_ctx.file_off += filesz;
  147. }
  148. static void fill_note_base(elf_note_base_t *note, const char *note_name,
  149. elf_word type, elf_word descsz)
  150. {
  151. note->namesz = strlen(note_name) + 1;
  152. note->descsz = descsz;
  153. note->type = type;
  154. mcd_memcpy(note->name, note_name, note->namesz);
  155. if (note->namesz & 3)
  156. memset(&note->name[note->namesz], 0, note->namesz & 3);
  157. }
  158. /* fill prstatus struct in note segment */
  159. static void fill_note_prstatus(elf_note_prstatus_t *prstatus, core_regset_type *regset)
  160. {
  161. fill_note_base((elf_note_base_t *)prstatus, "CORE", NT_PRSTATUS, sizeof(prstatus->desc));
  162. fill_note_prstatus_desc(&prstatus->desc[0], regset);
  163. }
  164. /* fill FP registers struct in note segment */
  165. static void fill_note_vfp_regset(elf_note_fpreg_entry_t *prstatus, fp_regset_type *regset)
  166. {
  167. fill_note_base((elf_note_base_t *)prstatus, "LINUX", NT_ARM_VFP, sizeof(prstatus->desc));
  168. fill_note_fpregset_desc(&prstatus->desc[0], regset);
  169. }
  170. void mcd_init(mcd_writeout_func_t func)
  171. {
  172. memset(&m_ctx, 0, sizeof(mcd_instance_t));
  173. m_ctx.stack_size = 1536;
  174. m_ctx.writeout_func = func;
  175. /* Automatically detect FPU support based on compiler definitions */
  176. m_ctx.with_fp = MCD_FPU_SUPPORT;
  177. }
  178. static void fill_one_threads_regset(core_regset_type *core_regset, fp_regset_type *fp_regset)
  179. {
  180. fill_note_prstatus(&m_ctx.tmp.prstatus, core_regset);
  181. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.prstatus, sizeof(elf_note_prstatus_t));
  182. if (m_ctx.with_fp)
  183. {
  184. fill_note_vfp_regset(&m_ctx.tmp.note_fp, fp_regset);
  185. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.note_fp, sizeof(elf_note_fpreg_entry_t));
  186. }
  187. }
  188. static void addr_align(uint32_t *addr, uint32_t *memlen)
  189. {
  190. *memlen += ((*addr) & (~CORE_MEM_LINE_MASK));
  191. *addr &= CORE_MEM_LINE_MASK;
  192. }
  193. // 生成.elf格式
  194. void mcd_gen_coredump(struct thread_info_ops *ops)
  195. {
  196. int note_size;
  197. uint32_t addr, memlen;
  198. int segment_count = ops->get_memarea_count(ops) + 1;
  199. fill_core_file_header(&m_ctx.tmp.elf_header, segment_count);
  200. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.elf_header, sizeof(elf_ehdr_t));
  201. m_ctx.file_off = sizeof(elf_ehdr_t) + segment_count * sizeof(elf_phdr_t);
  202. if (m_ctx.with_fp)
  203. note_size = (sizeof(elf_note_prstatus_t)
  204. + sizeof(elf_note_fpreg_entry_t))
  205. * ops->get_threads_count(ops);
  206. else
  207. note_size = sizeof(elf_note_prstatus_t)
  208. * ops->get_threads_count(ops);
  209. fill_program_header(&m_ctx.tmp.program_header, PT_NOTE, 0, note_size, 0, PF_R);
  210. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.program_header, sizeof(elf_phdr_t));
  211. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  212. {
  213. ops->get_memarea(ops, i, &addr, &memlen);
  214. addr_align(&addr, &memlen);
  215. fill_program_header(&m_ctx.tmp.program_header, PT_LOAD, addr,
  216. memlen, memlen,
  217. PF_R | PF_W);
  218. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.program_header, sizeof(elf_phdr_t));
  219. }
  220. /* Write all threads in index order */
  221. for (int i = 0; i < ops->get_threads_count(ops); i++)
  222. {
  223. ops->get_thread_regset(ops, i,
  224. &m_ctx.tmp_core_rset, &m_ctx.tmp_fp_rset);
  225. fill_one_threads_regset(&m_ctx.tmp_core_rset, &m_ctx.tmp_fp_rset);
  226. }
  227. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  228. {
  229. ops->get_memarea(ops, i, &addr, &memlen);
  230. addr_align(&addr, &memlen);
  231. m_ctx.writeout_func((uint8_t *)addr, memlen);
  232. }
  233. }
  234. int32_t mcd_corefile_size(struct thread_info_ops *ops)
  235. {
  236. int elf_size = 0;
  237. int segment_count;
  238. uint32_t addr, memlen;
  239. segment_count = ops->get_memarea_count(ops) + 1;
  240. elf_size = sizeof(elf_ehdr_t) + segment_count * sizeof(elf_phdr_t);
  241. if (m_ctx.with_fp)
  242. elf_size += (sizeof(elf_note_prstatus_t)
  243. + sizeof(elf_note_fpreg_entry_t))
  244. * ops->get_threads_count(ops);
  245. else
  246. elf_size += sizeof(elf_note_prstatus_t)
  247. * ops->get_threads_count(ops);
  248. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  249. {
  250. ops->get_memarea(ops, i, &addr, &memlen);
  251. addr_align(&addr, &memlen);
  252. elf_size += memlen;
  253. }
  254. return elf_size;
  255. }
  256. int32_t mcd_mini_dump_size(void)
  257. {
  258. struct thread_info_ops ops;
  259. mcd_mini_dump_ops(&ops);
  260. return mcd_corefile_size(&ops);
  261. }
  262. int32_t mcd_multi_dump_size(void)
  263. {
  264. struct thread_info_ops ops;
  265. mcd_rtos_thread_ops(&ops);
  266. return mcd_corefile_size(&ops);
  267. }
  268. static int32_t minidump_thr_cnts(struct thread_info_ops *ops)
  269. {
  270. return 1;
  271. }
  272. static int32_t minidump_cur_idx(struct thread_info_ops *ops)
  273. {
  274. return 0;
  275. }
  276. static void minidump_thr_rset(struct thread_info_ops *ops, int32_t idx,
  277. core_regset_type *core_regset,
  278. fp_regset_type *fp_regset)
  279. {
  280. mcd_memcpy(core_regset, get_cur_core_regset_address(), sizeof(core_regset_type));
  281. mcd_memcpy(fp_regset, get_cur_fp_regset_address(), sizeof(fp_regset_type));
  282. }
  283. static int32_t minidump_mem_cnts(struct thread_info_ops *ops)
  284. {
  285. return 1;
  286. }
  287. static int32_t minidump_memarea(struct thread_info_ops *ops, int32_t idx,
  288. uint32_t *addr, uint32_t *memlen)
  289. {
  290. *addr = current_core_regset.sp;
  291. *memlen = m_ctx.stack_size;
  292. return 0;
  293. }
  294. void mcd_mini_dump_ops(struct thread_info_ops *ops)
  295. {
  296. ops->get_threads_count = minidump_thr_cnts;
  297. ops->get_current_thread_idx = minidump_cur_idx;
  298. ops->get_thread_regset = minidump_thr_rset;
  299. ops->get_memarea_count = minidump_mem_cnts;
  300. ops->get_memarea = minidump_memarea;
  301. ops->priv = NULL;
  302. }
  303. core_regset_type *get_cur_core_regset_address(void)
  304. {
  305. return &current_core_regset;
  306. }
  307. fp_regset_type *get_cur_fp_regset_address(void)
  308. {
  309. return &current_fp_regset;
  310. }