Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

coredump.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. if (NULL == m_ctx.writeout_func)
  181. return;
  182. fill_note_prstatus(&m_ctx.tmp.prstatus, core_regset);
  183. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.prstatus, sizeof(elf_note_prstatus_t));
  184. if (m_ctx.with_fp)
  185. {
  186. fill_note_vfp_regset(&m_ctx.tmp.note_fp, fp_regset);
  187. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.note_fp, sizeof(elf_note_fpreg_entry_t));
  188. }
  189. }
  190. static void addr_align(uint32_t *addr, uint32_t *memlen)
  191. {
  192. *memlen += ((*addr) & (~CORE_MEM_LINE_MASK));
  193. *addr &= CORE_MEM_LINE_MASK;
  194. }
  195. // 生成.elf格式
  196. void mcd_gen_coredump(struct thread_info_ops *ops)
  197. {
  198. if (NULL == ops || NULL == ops->get_memarea_count || NULL == ops->get_memarea
  199. || NULL == ops->get_thread_regset || NULL == m_ctx.writeout_func)
  200. return;
  201. int note_size;
  202. uint32_t addr, memlen;
  203. int segment_count = ops->get_memarea_count(ops) + 1;
  204. fill_core_file_header(&m_ctx.tmp.elf_header, segment_count);
  205. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.elf_header, sizeof(elf_ehdr_t));
  206. m_ctx.file_off = sizeof(elf_ehdr_t) + segment_count * sizeof(elf_phdr_t);
  207. if (m_ctx.with_fp)
  208. note_size = (sizeof(elf_note_prstatus_t)
  209. + sizeof(elf_note_fpreg_entry_t))
  210. * ops->get_threads_count(ops);
  211. else
  212. note_size = sizeof(elf_note_prstatus_t)
  213. * ops->get_threads_count(ops);
  214. fill_program_header(&m_ctx.tmp.program_header, PT_NOTE, 0, note_size, 0, PF_R);
  215. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.program_header, sizeof(elf_phdr_t));
  216. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  217. {
  218. ops->get_memarea(ops, i, &addr, &memlen);
  219. addr_align(&addr, &memlen);
  220. fill_program_header(&m_ctx.tmp.program_header, PT_LOAD, addr,
  221. memlen, memlen,
  222. PF_R | PF_W);
  223. m_ctx.writeout_func((uint8_t *)&m_ctx.tmp.program_header, sizeof(elf_phdr_t));
  224. }
  225. /* Write all threads in index order */
  226. for (int i = 0; i < ops->get_threads_count(ops); i++)
  227. {
  228. ops->get_thread_regset(ops, i,
  229. &m_ctx.tmp_core_rset, &m_ctx.tmp_fp_rset);
  230. fill_one_threads_regset(&m_ctx.tmp_core_rset, &m_ctx.tmp_fp_rset);
  231. }
  232. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  233. {
  234. ops->get_memarea(ops, i, &addr, &memlen);
  235. addr_align(&addr, &memlen);
  236. m_ctx.writeout_func((uint8_t *)addr, memlen);
  237. }
  238. }
  239. int32_t mcd_corefile_size(struct thread_info_ops *ops)
  240. {
  241. if (NULL == ops || NULL == ops->get_memarea_count || NULL == ops->get_memarea)
  242. return 0;
  243. int elf_size = 0;
  244. int segment_count;
  245. uint32_t addr, memlen;
  246. segment_count = ops->get_memarea_count(ops) + 1;
  247. elf_size = sizeof(elf_ehdr_t) + segment_count * sizeof(elf_phdr_t);
  248. if (m_ctx.with_fp)
  249. elf_size += (sizeof(elf_note_prstatus_t)
  250. + sizeof(elf_note_fpreg_entry_t))
  251. * ops->get_threads_count(ops);
  252. else
  253. elf_size += sizeof(elf_note_prstatus_t)
  254. * ops->get_threads_count(ops);
  255. for (int i = 0; i < ops->get_memarea_count(ops); i++)
  256. {
  257. ops->get_memarea(ops, i, &addr, &memlen);
  258. addr_align(&addr, &memlen);
  259. elf_size += memlen;
  260. }
  261. return elf_size;
  262. }
  263. int32_t mcd_mini_dump_size(void)
  264. {
  265. struct thread_info_ops ops;
  266. mcd_mini_dump_ops(&ops);
  267. return mcd_corefile_size(&ops);
  268. }
  269. int32_t mcd_multi_dump_size(void)
  270. {
  271. struct thread_info_ops ops;
  272. mcd_rtos_thread_ops(&ops);
  273. return mcd_corefile_size(&ops);
  274. }
  275. static int32_t minidump_thr_cnts(struct thread_info_ops *ops)
  276. {
  277. return 1;
  278. }
  279. static int32_t minidump_cur_idx(struct thread_info_ops *ops)
  280. {
  281. return 0;
  282. }
  283. static void minidump_thr_rset(struct thread_info_ops *ops, int32_t idx,
  284. core_regset_type *core_regset,
  285. fp_regset_type *fp_regset)
  286. {
  287. mcd_memcpy(core_regset, get_cur_core_regset_address(), sizeof(core_regset_type));
  288. mcd_memcpy(fp_regset, get_cur_fp_regset_address(), sizeof(fp_regset_type));
  289. }
  290. static int32_t minidump_mem_cnts(struct thread_info_ops *ops)
  291. {
  292. return 1;
  293. }
  294. static int32_t minidump_memarea(struct thread_info_ops *ops, int32_t idx,
  295. uint32_t *addr, uint32_t *memlen)
  296. {
  297. *addr = current_core_regset.sp;
  298. *memlen = m_ctx.stack_size;
  299. return 0;
  300. }
  301. void mcd_mini_dump_ops(struct thread_info_ops *ops)
  302. {
  303. memset(ops, 0, sizeof(struct thread_info_ops));
  304. ops->get_threads_count = minidump_thr_cnts;
  305. ops->get_current_thread_idx = minidump_cur_idx;
  306. ops->get_thread_regset = minidump_thr_rset;
  307. ops->get_memarea_count = minidump_mem_cnts;
  308. ops->get_memarea = minidump_memarea;
  309. ops->priv = NULL;
  310. }
  311. core_regset_type *get_cur_core_regset_address(void)
  312. {
  313. return &current_core_regset;
  314. }
  315. fp_regset_type *get_cur_fp_regset_address(void)
  316. {
  317. return &current_fp_regset;
  318. }