mrdump_elf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* Copyright Statement:
  2. *
  3. * This software/firmware and related documentation ("MediaTek Software") are
  4. * protected under relevant copyright laws. The information contained herein
  5. * is confidential and proprietary to MediaTek Inc. and/or its licensors.
  6. * Without the prior written permission of MediaTek inc. and/or its licensors,
  7. * any reproduction, modification, use or disclosure of MediaTek Software,
  8. * and information contained herein, in whole or in part, shall be strictly prohibited.
  9. */
  10. /* MediaTek Inc. (C) 2016. All rights reserved.
  11. *
  12. * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
  13. * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
  14. * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
  15. * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
  18. * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
  19. * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
  20. * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
  21. * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
  22. * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
  23. * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
  24. * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
  25. * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
  26. * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
  27. * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
  28. * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
  29. * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
  30. */
  31. #include <malloc.h>
  32. #include <string.h>
  33. #include <printf.h>
  34. #include "mrdump_private.h"
  35. #include "mrdump_elf.h"
  36. #define mrdump_elf_setup_elfhdr(elfp, machid, elfhdr_t, elfphdr_t, phdrcount) \
  37. elfp->e_type = ET_CORE; \
  38. elfp->e_machine = machid; \
  39. elfp->e_version = EV_CURRENT; \
  40. elfp->e_entry = 0; \
  41. elfp->e_phoff = sizeof(elfhdr_t); \
  42. elfp->e_shoff = 0; \
  43. elfp->e_flags = ELF_CORE_EFLAGS; \
  44. elfp->e_ehsize = sizeof(elfhdr_t); \
  45. elfp->e_phentsize = sizeof(elfphdr_t); \
  46. elfp->e_phnum = phdrcount; \
  47. elfp->e_shentsize = 0; \
  48. elfp->e_shnum = 0; \
  49. elfp->e_shstrndx = 0; \
  50. static inline void mrdump_elf_setup_eident(unsigned char e_ident[EI_NIDENT], unsigned char elfclasz)
  51. {
  52. memcpy(e_ident, ELFMAG, SELFMAG);
  53. e_ident[EI_CLASS] = elfclasz;
  54. e_ident[EI_DATA] = ELFDATA2LSB;
  55. e_ident[EI_VERSION] = EV_CURRENT;
  56. e_ident[EI_OSABI] = ELFOSABI_NONE;
  57. memset(e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
  58. }
  59. static uint32_t roundup(uint32_t x, uint32_t y)
  60. {
  61. return ((x + y - 1) / y) * y;
  62. }
  63. /* An ELF note in memory */
  64. struct memelfnote {
  65. const char *name;
  66. int type;
  67. unsigned int datasz;
  68. void *data;
  69. };
  70. static int notesize(struct memelfnote *en)
  71. {
  72. int sz;
  73. sz = sizeof(struct elf32_note);
  74. sz += roundup((strlen(en->name) + 1), 4);
  75. sz += roundup(en->datasz, 4);
  76. return sz;
  77. }
  78. static uint8_t *storenote(struct memelfnote *men, uint8_t *bufp)
  79. {
  80. struct elf32_note en;
  81. en.n_namesz = strlen(men->name) + 1;
  82. en.n_descsz = men->datasz;
  83. en.n_type = men->type;
  84. memcpy(bufp, &en, sizeof(en));
  85. bufp += sizeof(en);
  86. memcpy(bufp, men->name, en.n_namesz);
  87. bufp += en.n_namesz;
  88. bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
  89. memcpy(bufp, men->data, men->datasz);
  90. bufp += men->datasz;
  91. bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
  92. return bufp;
  93. }
  94. static uint8_t *mrdump_core32_write_cpu_note(const struct mrdump_control_block *mrdump_cb, int cpu, struct elf32_phdr *nhdr, uint8_t *bufp)
  95. {
  96. struct memelfnote notes;
  97. struct elf32_arm_prstatus prstatus;
  98. char cpustr[16];
  99. memset(&prstatus, 0, sizeof(struct elf32_arm_prstatus));
  100. snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu);
  101. /* set up the process status */
  102. notes.name = cpustr;
  103. notes.type = NT_PRSTATUS;
  104. notes.datasz = sizeof(struct elf32_arm_prstatus);
  105. notes.data = &prstatus;
  106. prstatus.pr_pid = cpu + 1;
  107. memcpy(&prstatus.pr_reg, (unsigned long*)&mrdump_cb->crash_record.cpu_regs[cpu].arm32_regs, sizeof(elf_arm_gregset_t));
  108. nhdr->p_filesz += notesize(&notes);
  109. return storenote(&notes, bufp);
  110. }
  111. static uint8_t *mrdump_core32_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
  112. {
  113. struct memelfnote notes;
  114. struct elf_mrdump_machdesc machdesc;
  115. const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
  116. memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
  117. notes.name = "MRDUMP01";
  118. notes.type = NT_MRDUMP_MACHDESC;
  119. notes.datasz = sizeof(struct elf_mrdump_machdesc);
  120. notes.data = &machdesc;
  121. machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
  122. machdesc.nr_cpus = kparams->nr_cpus;
  123. machdesc.phys_offset = kparams->phys_offset;
  124. machdesc.page_offset = kparams->page_offset;
  125. machdesc.high_memory = kparams->high_memory;
  126. machdesc.kimage_vaddr = kparams->kimage_vaddr;
  127. machdesc.modules_start = kparams->modules_start;
  128. machdesc.modules_end = kparams->modules_end;
  129. machdesc.vmalloc_start = kparams->vmalloc_start;
  130. machdesc.vmalloc_end = kparams->vmalloc_end;
  131. machdesc.master_page_table = kparams->master_page_table;
  132. nhdr->p_filesz += notesize(&notes);
  133. return storenote(&notes, bufp);
  134. }
  135. static uint8_t *mrdump_core32_write_cb(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
  136. {
  137. struct memelfnote notes;
  138. uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)mrdump_cb;
  139. notes.name = MRDUMP_GO_DUMP;
  140. notes.type = NT_MRDUMP_CBLOCK;
  141. notes.datasz = sizeof(mrdump_cb_paddr);
  142. notes.data = &mrdump_cb_paddr;
  143. nhdr->p_filesz += notesize(&notes);
  144. return storenote(&notes, bufp);
  145. }
  146. static void mrdump_core32_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
  147. {
  148. struct elf32_phdr *nhdr, *phdr;
  149. struct elf32_hdr *elf;
  150. off_t offset = 0;
  151. const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
  152. uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
  153. elf = (struct elf32_hdr *) bufp;
  154. bufp += sizeof(struct elf32_hdr);
  155. offset += sizeof(struct elf32_hdr);
  156. nhdr = (struct elf32_phdr *) bufp;
  157. bufp += sizeof(struct elf32_phdr);
  158. offset += sizeof(struct elf32_phdr);
  159. memset(nhdr, 0, sizeof(struct elf32_phdr));
  160. nhdr->p_type = PT_NOTE;
  161. unsigned long long foffset = MRDUMP_CORE_HEADER_SIZE;
  162. int i;
  163. for (i = 1; memlist[i].address != 0;i++) {
  164. phdr = (struct elf32_phdr *) bufp;
  165. bufp += sizeof(struct elf32_phdr);
  166. offset += sizeof(struct elf32_phdr);
  167. phdr->p_type = PT_LOAD;
  168. phdr->p_flags = PF_R|PF_W|PF_X;
  169. phdr->p_offset = foffset;
  170. phdr->p_vaddr = 0;
  171. phdr->p_paddr = memlist[i].address;
  172. phdr->p_filesz = memlist[i].size;
  173. phdr->p_memsz = memlist[i].size;
  174. phdr->p_align = 0;
  175. foffset += phdr->p_filesz;
  176. }
  177. mrdump_elf_setup_eident(elf->e_ident, ELFCLASS32);
  178. mrdump_elf_setup_elfhdr(elf, EM_ARM, struct elf32_hdr, struct elf32_phdr, i);
  179. nhdr->p_offset = offset;
  180. /* NT_PRPSINFO */
  181. struct elf32_prpsinfo prpsinfo;
  182. struct memelfnote notes;
  183. /* set up the process info */
  184. notes.name = CORE_STR;
  185. notes.type = NT_PRPSINFO;
  186. notes.datasz = sizeof(struct elf32_prpsinfo);
  187. notes.data = &prpsinfo;
  188. memset(&prpsinfo, 0, sizeof(struct elf32_prpsinfo));
  189. prpsinfo.pr_state = 0;
  190. prpsinfo.pr_sname = 'R';
  191. prpsinfo.pr_zomb = 0;
  192. prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
  193. strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
  194. strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
  195. nhdr->p_filesz += notesize(&notes);
  196. bufp = storenote(&notes, bufp);
  197. bufp = mrdump_core32_write_machdesc(mrdump_cb, nhdr, bufp);
  198. /* Store pre-cpu backtrace */
  199. bufp = mrdump_core32_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
  200. for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
  201. if (cpu != mrdump_cb->crash_record.fault_cpu) {
  202. bufp = mrdump_core32_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
  203. }
  204. }
  205. /* store mrdump control block */
  206. bufp = mrdump_core32_write_cb(mrdump_cb, nhdr, bufp);
  207. }
  208. static int notesize64(struct memelfnote *en)
  209. {
  210. int sz;
  211. sz = sizeof(struct elf64_note);
  212. sz += roundup((strlen(en->name) + 1), 4);
  213. sz += roundup(en->datasz, 4);
  214. return sz;
  215. }
  216. static uint8_t *storenote64(struct memelfnote *men, uint8_t *bufp)
  217. {
  218. struct elf64_note en;
  219. en.n_namesz = strlen(men->name) + 1;
  220. en.n_descsz = men->datasz;
  221. en.n_type = men->type;
  222. memcpy(bufp, &en, sizeof(en));
  223. bufp += sizeof(en);
  224. memcpy(bufp, men->name, en.n_namesz);
  225. bufp += en.n_namesz;
  226. bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
  227. memcpy(bufp, men->data, men->datasz);
  228. bufp += men->datasz;
  229. bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
  230. return bufp;
  231. }
  232. static uint8_t *mrdump_core64_write_cpu_note(const struct mrdump_control_block *mrdump_cb, int cpu, struct elf64_phdr *nhdr, uint8_t *bufp)
  233. {
  234. struct memelfnote notes;
  235. struct elf_arm64_prstatus64 prstatus;
  236. char cpustr[16];
  237. memset(&prstatus, 0, sizeof(struct elf_arm64_prstatus64));
  238. snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu);
  239. /* set up the process status */
  240. notes.name = cpustr;
  241. notes.type = NT_PRSTATUS;
  242. notes.datasz = sizeof(struct elf_arm64_prstatus64);
  243. notes.data = &prstatus;
  244. prstatus.pr_pid = cpu + 1;
  245. memcpy(&prstatus.pr_reg, &mrdump_cb->crash_record.cpu_regs[cpu].arm64_regs, sizeof(elf_arm64_gregset_t));
  246. nhdr->p_filesz += notesize64(&notes);
  247. return storenote64(&notes, bufp);
  248. }
  249. static uint8_t *mrdump_core64_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
  250. {
  251. struct memelfnote notes;
  252. struct elf_mrdump_machdesc machdesc;
  253. const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
  254. memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
  255. notes.name = "MRDUMP01";
  256. notes.type = NT_MRDUMP_MACHDESC;
  257. notes.datasz = sizeof(struct elf_mrdump_machdesc);
  258. notes.data = &machdesc;
  259. machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
  260. machdesc.nr_cpus = kparams->nr_cpus;
  261. machdesc.phys_offset = kparams->phys_offset;
  262. machdesc.page_offset = kparams->page_offset;
  263. machdesc.high_memory = kparams->high_memory;
  264. machdesc.kimage_vaddr = kparams->kimage_vaddr;
  265. machdesc.modules_start = kparams->modules_start;
  266. machdesc.modules_end = kparams->modules_end;
  267. machdesc.vmalloc_start = kparams->vmalloc_start;
  268. machdesc.vmalloc_end = kparams->vmalloc_end;
  269. machdesc.master_page_table = kparams->master_page_table;
  270. nhdr->p_filesz += notesize64(&notes);
  271. return storenote64(&notes, bufp);
  272. }
  273. static uint8_t *mrdump_core64_write_vmcoreinfo(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
  274. {
  275. struct memelfnote notes;
  276. const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
  277. char vmcoreinfo[512];
  278. memset(vmcoreinfo, 0, sizeof(vmcoreinfo));
  279. notes.name = "VMCOREINFO";
  280. notes.type = 0;
  281. notes.datasz = 0;
  282. notes.data = &vmcoreinfo;
  283. snprintf(vmcoreinfo, sizeof(vmcoreinfo),
  284. "PAGESIZE=4096\n"
  285. "NUMBER(kimage_voffset)=0x%llx\n"
  286. "SYMBOL(_stext)=0x%llx\n"
  287. "NUMBER(VA_BITS)=%d\n"
  288. "NUMBER(PHYS_OFFSET)=0x%llx\n",
  289. (uint64_t)kparams->kimage_voffset,
  290. (uint64_t)kparams->kimage_stext_real,
  291. 39,
  292. (uint64_t)kparams->phys_offset);
  293. notes.datasz = strlen(vmcoreinfo);
  294. nhdr->p_filesz += notesize64(&notes);
  295. return storenote64(&notes, bufp);
  296. }
  297. static uint8_t *mrdump_core64_write_cb(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
  298. {
  299. struct memelfnote notes;
  300. uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)mrdump_cb;
  301. notes.name = MRDUMP_GO_DUMP;
  302. notes.type = NT_MRDUMP_CBLOCK;
  303. notes.datasz = sizeof(mrdump_cb_paddr);
  304. notes.data = &mrdump_cb_paddr;
  305. nhdr->p_filesz += notesize64(&notes);
  306. return storenote64(&notes, bufp);
  307. }
  308. static void mrdump_core64_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
  309. {
  310. struct elf64_phdr *nhdr, *phdr;
  311. struct elf64_hdr *elf;
  312. off_t offset = 0;
  313. const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
  314. uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
  315. elf = (struct elf64_hdr *) bufp;
  316. bufp += sizeof(struct elf64_hdr);
  317. offset += sizeof(struct elf64_hdr);
  318. nhdr = (struct elf64_phdr *) bufp;
  319. bufp += sizeof(struct elf64_phdr);
  320. offset += sizeof(struct elf64_phdr);
  321. memset(nhdr, 0, sizeof(struct elf64_phdr));
  322. nhdr->p_type = PT_NOTE;
  323. unsigned long long foffset = MRDUMP_CORE_HEADER_SIZE;
  324. int i;
  325. for (i = 1; memlist[i].address != 0;i++) {
  326. phdr = (struct elf64_phdr *) bufp;
  327. bufp += sizeof(struct elf64_phdr);
  328. offset += sizeof(struct elf64_phdr);
  329. phdr->p_type = PT_LOAD;
  330. phdr->p_flags = PF_R|PF_W|PF_X;
  331. phdr->p_offset = foffset;
  332. phdr->p_vaddr = 0;
  333. phdr->p_paddr = memlist[i].address;
  334. phdr->p_filesz = memlist[i].size;
  335. phdr->p_memsz = memlist[i].size;
  336. phdr->p_align = 0;
  337. foffset += phdr->p_filesz;
  338. }
  339. mrdump_elf_setup_eident(elf->e_ident, ELFCLASS64);
  340. mrdump_elf_setup_elfhdr(elf, EM_AARCH64, struct elf64_hdr, struct elf64_phdr, i);
  341. nhdr->p_offset = offset;
  342. /* NT_PRPSINFO */
  343. struct elf_prpsinfo64 prpsinfo;
  344. struct memelfnote notes;
  345. /* set up the process info */
  346. notes.name = CORE_STR;
  347. notes.type = NT_PRPSINFO;
  348. notes.datasz = sizeof(struct elf_prpsinfo64);
  349. notes.data = &prpsinfo;
  350. memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo64));
  351. prpsinfo.pr_state = 0;
  352. prpsinfo.pr_sname = 'R';
  353. prpsinfo.pr_zomb = 0;
  354. prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
  355. strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
  356. strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
  357. nhdr->p_filesz += notesize64(&notes);
  358. bufp = storenote64(&notes, bufp);
  359. bufp = mrdump_core64_write_machdesc(mrdump_cb, nhdr, bufp);
  360. bufp = mrdump_core64_write_vmcoreinfo(mrdump_cb, nhdr, bufp);
  361. /* Store pre-cpu backtrace */
  362. bufp = mrdump_core64_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
  363. for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
  364. if (cpu != mrdump_cb->crash_record.fault_cpu) {
  365. bufp = mrdump_core64_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
  366. }
  367. }
  368. /* store mrdump control block */
  369. bufp = mrdump_core64_write_cb(mrdump_cb, nhdr, bufp);
  370. }
  371. void mrdump_core_header_init(const struct mrdump_control_block *kparams, const struct kzip_addlist *memlist)
  372. {
  373. if (kparams->machdesc.page_offset <= 0xffffffffULL) {
  374. voprintf_info("32b kernel detected\n");
  375. mrdump_core32_header_init(kparams, memlist);
  376. } else {
  377. voprintf_info("64b kernel detected\n");
  378. mrdump_core64_header_init(kparams, memlist);
  379. }
  380. }