ramdump.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * ramdump.c - core analysis suite
  3. *
  4. * Copyright (c) 2014 Vinayak Menon <vinayakm.list@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * Author: Vinayak Menon <vinayakm.list@gmail.com>
  17. */
  18. #define _LARGEFILE64_SOURCE 1 /* stat64() */
  19. #include "defs.h"
  20. #include <elf.h>
  21. struct ramdump_def {
  22. char *path;
  23. int rfd;
  24. ulonglong start_paddr;
  25. ulonglong end_paddr;
  26. };
  27. static struct ramdump_def *ramdump;
  28. static int nodes;
  29. static char *user_elf = NULL;
  30. static char elf_default[] = "/var/tmp/ramdump_elf_XXXXXX";
  31. static void alloc_elf_header(Elf64_Ehdr *ehdr, ushort e_machine)
  32. {
  33. memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
  34. ehdr->e_ident[EI_CLASS] = ELFCLASS64;
  35. ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
  36. ehdr->e_ident[EI_VERSION] = EV_CURRENT;
  37. ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
  38. ehdr->e_ident[EI_ABIVERSION] = 0;
  39. memset(ehdr->e_ident+EI_PAD, 0,
  40. EI_NIDENT-EI_PAD);
  41. ehdr->e_type = ET_CORE;
  42. ehdr->e_machine = e_machine;
  43. ehdr->e_version = EV_CURRENT;
  44. ehdr->e_entry = 0;
  45. ehdr->e_phoff = sizeof(Elf64_Ehdr);
  46. ehdr->e_shoff = 0;
  47. ehdr->e_flags = 0;
  48. ehdr->e_ehsize = sizeof(Elf64_Ehdr);
  49. ehdr->e_phentsize = sizeof(Elf64_Phdr);
  50. ehdr->e_phnum = 1 + nodes;
  51. ehdr->e_shentsize = 0;
  52. ehdr->e_shnum = 0;
  53. ehdr->e_shstrndx = 0;
  54. }
  55. static int alloc_program_headers(Elf64_Phdr *phdr)
  56. {
  57. unsigned int i;
  58. struct stat64 st;
  59. for (i = 0; i < nodes; i++, phdr++) {
  60. phdr[i].p_type = PT_LOAD;
  61. if (0 > stat64(ramdump[i].path, &st)) {
  62. error(INFO, "ramdump stat failed\n");
  63. return -1;
  64. }
  65. phdr[i].p_filesz = st.st_size;
  66. phdr[i].p_memsz = phdr[i].p_filesz;
  67. phdr[i].p_vaddr = 0;
  68. phdr[i].p_paddr = ramdump[i].start_paddr;
  69. ramdump[i].end_paddr = ramdump[i].start_paddr + st.st_size - 1;
  70. phdr[i].p_flags = PF_R | PF_W | PF_X;
  71. phdr[i].p_align = 0;
  72. }
  73. return 0;
  74. }
  75. static char *write_elf(Elf64_Phdr *load, Elf64_Ehdr *e_head, size_t data_offset)
  76. {
  77. #define CPY_BUF_SZ 4096
  78. int fd1, fd2, i, err = 1;
  79. char *buf;
  80. char *out_elf;
  81. size_t rd, len, offset;
  82. buf = (char *)malloc(CPY_BUF_SZ);
  83. offset = data_offset;
  84. if (user_elf) {
  85. fd2 = open(user_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
  86. if (fd2 < 0) {
  87. error(INFO, "%s open error, %s\n",
  88. user_elf, strerror(errno));
  89. goto end1;
  90. }
  91. out_elf = user_elf;
  92. } else {
  93. fd2 = mkstemp(elf_default);
  94. if (fd2 < 0) {
  95. error(INFO, "%s open error, %s\n",
  96. elf_default, strerror(errno));
  97. goto end1;
  98. }
  99. out_elf = elf_default;
  100. pc->flags2 |= RAMDUMP;
  101. }
  102. if (user_elf) {
  103. sprintf(buf, "creating ELF dumpfile: %s", out_elf);
  104. please_wait(buf);
  105. } else if (CRASHDEBUG(1))
  106. fprintf(fp, "creating temporary ELF header: %s\n\n",
  107. elf_default);
  108. while (offset > 0) {
  109. len = write(fd2, e_head + (data_offset - offset), offset);
  110. if (len < 0) {
  111. error(INFO, "ramdump write error, %s\n",
  112. strerror(errno));
  113. goto end;
  114. }
  115. offset -= len;
  116. }
  117. if (user_elf) {
  118. for (i = 0; i < nodes; i++) {
  119. offset = load[i].p_offset;
  120. fd1 = open(ramdump[i].path, O_RDONLY, S_IRUSR);
  121. if (fd1 < 0) {
  122. error(INFO, "%s open error, %s\n",
  123. ramdump[i].path, strerror(errno));
  124. goto end;
  125. }
  126. lseek(fd2, (off_t)offset, SEEK_SET);
  127. while ((rd = read(fd1, buf, CPY_BUF_SZ)) > 0) {
  128. if (write(fd2, buf, rd) != rd) {
  129. error(INFO, "%s write error, %s\n",
  130. ramdump[i].path,
  131. strerror(errno));
  132. close(fd1);
  133. goto end;
  134. }
  135. }
  136. close(fd1);
  137. }
  138. please_wait_done();
  139. }
  140. err = 0;
  141. end:
  142. close(fd2);
  143. end1:
  144. free(buf);
  145. return err ? NULL : out_elf;
  146. }
  147. static void alloc_notes(Elf64_Phdr *notes)
  148. {
  149. /* Nothing filled in as of now */
  150. notes->p_type = PT_NOTE;
  151. notes->p_offset = 0;
  152. notes->p_vaddr = 0;
  153. notes->p_paddr = 0;
  154. notes->p_filesz = 0;
  155. notes->p_memsz = 0;
  156. notes->p_flags = 0;
  157. notes->p_align = 0;
  158. }
  159. char *ramdump_to_elf(void)
  160. {
  161. int i;
  162. char *ptr, *e_file = NULL;
  163. ushort e_machine = 0;
  164. size_t offset, data_offset;
  165. size_t l_offset;
  166. Elf64_Phdr *notes, *load;
  167. Elf64_Ehdr *e_head;
  168. if (machine_type("ARM"))
  169. e_machine = EM_ARM;
  170. else if (machine_type("ARM64"))
  171. e_machine = EM_AARCH64;
  172. else
  173. error(FATAL, "ramdump: unsupported machine type: %s\n",
  174. MACHINE_TYPE);
  175. e_head = (Elf64_Ehdr *)malloc(sizeof(Elf64_Ehdr) +
  176. nodes * sizeof(Elf64_Phdr) + CPY_BUF_SZ * 2);
  177. ptr = (char *)e_head;
  178. offset = 0;
  179. alloc_elf_header(e_head, e_machine);
  180. ptr += sizeof(Elf64_Ehdr);
  181. offset += sizeof(Elf64_Ehdr);
  182. notes = (Elf64_Phdr *)ptr;
  183. alloc_notes(notes);
  184. offset += sizeof(Elf64_Phdr);
  185. ptr += sizeof(Elf64_Phdr);
  186. load = (Elf64_Phdr *)ptr;
  187. if (alloc_program_headers(load))
  188. goto end;
  189. offset += sizeof(Elf64_Phdr) * nodes;
  190. ptr += sizeof(Elf64_Phdr) * nodes;
  191. /* Empty note */
  192. notes->p_offset = offset;
  193. l_offset = offset;
  194. data_offset = offset;
  195. for (i = 0; i < nodes; i++) {
  196. load[i].p_offset = l_offset;
  197. l_offset += load[i].p_filesz;
  198. }
  199. e_file = write_elf(load, e_head, data_offset);
  200. end:
  201. free(e_head);
  202. return e_file;
  203. }
  204. int is_ramdump(char *p)
  205. {
  206. char *x = NULL, *y = NULL, *pat;
  207. size_t len;
  208. char *pattern;
  209. int err = 0;
  210. if (nodes || !strchr(p, '@'))
  211. return 0;
  212. len = strlen(p);
  213. pattern = (char *)malloc(len + 1);
  214. strlcpy(pattern, p, len + 1);
  215. pat = pattern;
  216. while ((pat = strtok_r(pat, ",", &x))) {
  217. if ((pat = strtok_r(pat, "@", &y))) {
  218. nodes++;
  219. ramdump = realloc(ramdump,
  220. sizeof(struct ramdump_def) * nodes);
  221. if (!ramdump)
  222. error(FATAL, "realloc failure\n");
  223. ramdump[nodes - 1].path = pat;
  224. pat = strtok_r(NULL, "@", &y);
  225. ramdump[nodes - 1].start_paddr =
  226. htoll(pat, RETURN_ON_ERROR, &err);
  227. if (err == TRUE)
  228. error(FATAL, "Invalid ramdump address\n");
  229. if ((ramdump[nodes - 1].rfd =
  230. open(ramdump[nodes - 1].path, O_RDONLY)) < 0)
  231. error(FATAL,
  232. "ramdump %s open failed:%s\n",
  233. ramdump[nodes - 1].path,
  234. strerror(errno));
  235. }
  236. pat = NULL;
  237. }
  238. return nodes;
  239. }
  240. void ramdump_elf_output_file(char *opt)
  241. {
  242. user_elf = opt;
  243. }
  244. void ramdump_cleanup(void)
  245. {
  246. if (!user_elf)
  247. unlink(elf_default);
  248. }
  249. int
  250. read_ramdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
  251. {
  252. off_t offset;
  253. int i, found;
  254. struct ramdump_def *r = &ramdump[0];
  255. offset = 0;
  256. for (i = found = 0; i < nodes; i++) {
  257. r = &ramdump[i];
  258. if ((paddr >= r->start_paddr) &&
  259. (paddr <= r->end_paddr)) {
  260. offset = (off_t)paddr - (off_t)r->start_paddr;
  261. found++;
  262. break;
  263. }
  264. }
  265. if (!found) {
  266. if (CRASHDEBUG(8))
  267. fprintf(fp, "read_ramdump: READ_ERROR: "
  268. "offset not found for paddr: %llx\n",
  269. (ulonglong)paddr);
  270. return READ_ERROR;
  271. }
  272. if (CRASHDEBUG(8))
  273. fprintf(fp,
  274. "read_ramdump: addr: %lx paddr: %llx cnt: %d offset: %llx\n",
  275. addr, (ulonglong)paddr, cnt, (ulonglong)offset);
  276. if (lseek(r->rfd, offset, SEEK_SET) == -1) {
  277. if (CRASHDEBUG(8))
  278. fprintf(fp, "read_ramdump: SEEK_ERROR: "
  279. "offset: %llx\n", (ulonglong)offset);
  280. return SEEK_ERROR;
  281. }
  282. if (read(r->rfd, bufptr, cnt) != cnt) {
  283. if (CRASHDEBUG(8))
  284. fprintf(fp, "read_ramdump: READ_ERROR: "
  285. "offset: %llx\n", (ulonglong)offset);
  286. return READ_ERROR;
  287. }
  288. return cnt;
  289. }
  290. void
  291. show_ramdump_files(void)
  292. {
  293. int i;
  294. fprintf(fp, "%s [temporary ELF header]\n", elf_default);
  295. for (i = 0; i < nodes; i++) {
  296. fprintf(fp, "%s %s",
  297. i ? "\n" : "", ramdump[i].path);
  298. }
  299. }
  300. void
  301. dump_ramdump_data()
  302. {
  303. int i;
  304. if (!user_elf && !is_ramdump_image())
  305. return;
  306. fprintf(fp, "\nramdump data:\n");
  307. fprintf(fp, " user_elf: %s\n",
  308. user_elf ? user_elf : "(unused)");
  309. fprintf(fp, " elf_default: %s\n",
  310. user_elf ? "(unused)" : elf_default);
  311. fprintf(fp, " nodes: %d\n", nodes);
  312. for (i = 0; i < nodes; i++) {
  313. fprintf(fp, " ramdump[%d]:\n", i);
  314. fprintf(fp, " path: %s\n",
  315. ramdump[i].path);
  316. fprintf(fp, " rfd: %d\n",
  317. ramdump[i].rfd);
  318. fprintf(fp, " start_paddr: %llx\n",
  319. (ulonglong)ramdump[i].start_paddr);
  320. fprintf(fp, " end_paddr: %llx\n",
  321. (ulonglong)ramdump[i].end_paddr);
  322. }
  323. fprintf(fp, "\n");
  324. }
  325. int
  326. is_ramdump_image(void)
  327. {
  328. return (pc->flags2 & RAMDUMP ? TRUE : FALSE);
  329. }