~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/proc/vmcore.c

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      fs/proc/vmcore.c Interface for accessing the crash
  3  *                               dump from the system's previous life.
  4  *      Heavily borrowed from fs/proc/kcore.c
  5  *      Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
  6  *      Copyright (C) IBM Corporation, 2004. All rights reserved
  7  *
  8  */
  9 
 10 #include <linux/mm.h>
 11 #include <linux/proc_fs.h>
 12 #include <linux/user.h>
 13 #include <linux/elf.h>
 14 #include <linux/elfcore.h>
 15 #include <linux/highmem.h>
 16 #include <linux/bootmem.h>
 17 #include <linux/init.h>
 18 #include <linux/crash_dump.h>
 19 #include <linux/list.h>
 20 #include <asm/uaccess.h>
 21 #include <asm/io.h>
 22 
 23 /* List representing chunks of contiguous memory areas and their offsets in
 24  * vmcore file.
 25  */
 26 static LIST_HEAD(vmcore_list);
 27 
 28 /* Stores the pointer to the buffer containing kernel elf core headers. */
 29 static char *elfcorebuf;
 30 static size_t elfcorebuf_sz;
 31 
 32 /* Total size of vmcore file. */
 33 static u64 vmcore_size;
 34 
 35 static struct proc_dir_entry *proc_vmcore = NULL;
 36 
 37 /* Reads a page from the oldmem device from given offset. */
 38 static ssize_t read_from_oldmem(char *buf, size_t count,
 39                                 u64 *ppos, int userbuf)
 40 {
 41         unsigned long pfn, offset;
 42         size_t nr_bytes;
 43         ssize_t read = 0, tmp;
 44 
 45         if (!count)
 46                 return 0;
 47 
 48         offset = (unsigned long)(*ppos % PAGE_SIZE);
 49         pfn = (unsigned long)(*ppos / PAGE_SIZE);
 50 
 51         do {
 52                 if (count > (PAGE_SIZE - offset))
 53                         nr_bytes = PAGE_SIZE - offset;
 54                 else
 55                         nr_bytes = count;
 56 
 57                 tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
 58                 if (tmp < 0)
 59                         return tmp;
 60                 *ppos += nr_bytes;
 61                 count -= nr_bytes;
 62                 buf += nr_bytes;
 63                 read += nr_bytes;
 64                 ++pfn;
 65                 offset = 0;
 66         } while (count);
 67 
 68         return read;
 69 }
 70 
 71 /* Maps vmcore file offset to respective physical address in memroy. */
 72 static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list,
 73                                         struct vmcore **m_ptr)
 74 {
 75         struct vmcore *m;
 76         u64 paddr;
 77 
 78         list_for_each_entry(m, vc_list, list) {
 79                 u64 start, end;
 80                 start = m->offset;
 81                 end = m->offset + m->size - 1;
 82                 if (offset >= start && offset <= end) {
 83                         paddr = m->paddr + offset - start;
 84                         *m_ptr = m;
 85                         return paddr;
 86                 }
 87         }
 88         *m_ptr = NULL;
 89         return 0;
 90 }
 91 
 92 /* Read from the ELF header and then the crash dump. On error, negative value is
 93  * returned otherwise number of bytes read are returned.
 94  */
 95 static ssize_t read_vmcore(struct file *file, char __user *buffer,
 96                                 size_t buflen, loff_t *fpos)
 97 {
 98         ssize_t acc = 0, tmp;
 99         size_t tsz;
100         u64 start, nr_bytes;
101         struct vmcore *curr_m = NULL;
102 
103         if (buflen == 0 || *fpos >= vmcore_size)
104                 return 0;
105 
106         /* trim buflen to not go beyond EOF */
107         if (buflen > vmcore_size - *fpos)
108                 buflen = vmcore_size - *fpos;
109 
110         /* Read ELF core header */
111         if (*fpos < elfcorebuf_sz) {
112                 tsz = elfcorebuf_sz - *fpos;
113                 if (buflen < tsz)
114                         tsz = buflen;
115                 if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
116                         return -EFAULT;
117                 buflen -= tsz;
118                 *fpos += tsz;
119                 buffer += tsz;
120                 acc += tsz;
121 
122                 /* leave now if filled buffer already */
123                 if (buflen == 0)
124                         return acc;
125         }
126 
127         start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
128         if (!curr_m)
129                 return -EINVAL;
130         if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
131                 tsz = buflen;
132 
133         /* Calculate left bytes in current memory segment. */
134         nr_bytes = (curr_m->size - (start - curr_m->paddr));
135         if (tsz > nr_bytes)
136                 tsz = nr_bytes;
137 
138         while (buflen) {
139                 tmp = read_from_oldmem(buffer, tsz, &start, 1);
140                 if (tmp < 0)
141                         return tmp;
142                 buflen -= tsz;
143                 *fpos += tsz;
144                 buffer += tsz;
145                 acc += tsz;
146                 if (start >= (curr_m->paddr + curr_m->size)) {
147                         if (curr_m->list.next == &vmcore_list)
148                                 return acc;     /*EOF*/
149                         curr_m = list_entry(curr_m->list.next,
150                                                 struct vmcore, list);
151                         start = curr_m->paddr;
152                 }
153                 if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
154                         tsz = buflen;
155                 /* Calculate left bytes in current memory segment. */
156                 nr_bytes = (curr_m->size - (start - curr_m->paddr));
157                 if (tsz > nr_bytes)
158                         tsz = nr_bytes;
159         }
160         return acc;
161 }
162 
163 static const struct file_operations proc_vmcore_operations = {
164         .read           = read_vmcore,
165 };
166 
167 static struct vmcore* __init get_new_element(void)
168 {
169         return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
170 }
171 
172 static u64 __init get_vmcore_size_elf64(char *elfptr)
173 {
174         int i;
175         u64 size;
176         Elf64_Ehdr *ehdr_ptr;
177         Elf64_Phdr *phdr_ptr;
178 
179         ehdr_ptr = (Elf64_Ehdr *)elfptr;
180         phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
181         size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr));
182         for (i = 0; i < ehdr_ptr->e_phnum; i++) {
183                 size += phdr_ptr->p_memsz;
184                 phdr_ptr++;
185         }
186         return size;
187 }
188 
189 static u64 __init get_vmcore_size_elf32(char *elfptr)
190 {
191         int i;
192         u64 size;
193         Elf32_Ehdr *ehdr_ptr;
194         Elf32_Phdr *phdr_ptr;
195 
196         ehdr_ptr = (Elf32_Ehdr *)elfptr;
197         phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
198         size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr));
199         for (i = 0; i < ehdr_ptr->e_phnum; i++) {
200                 size += phdr_ptr->p_memsz;
201                 phdr_ptr++;
202         }
203         return size;
204 }
205 
206 /* Merges all the PT_NOTE headers into one. */
207 static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
208                                                 struct list_head *vc_list)
209 {
210         int i, nr_ptnote=0, rc=0;
211         char *tmp;
212         Elf64_Ehdr *ehdr_ptr;
213         Elf64_Phdr phdr, *phdr_ptr;
214         Elf64_Nhdr *nhdr_ptr;
215         u64 phdr_sz = 0, note_off;
216 
217         ehdr_ptr = (Elf64_Ehdr *)elfptr;
218         phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
219         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
220                 int j;
221                 void *notes_section;
222                 struct vmcore *new;
223                 u64 offset, max_sz, sz, real_sz = 0;
224                 if (phdr_ptr->p_type != PT_NOTE)
225                         continue;
226                 nr_ptnote++;
227                 max_sz = phdr_ptr->p_memsz;
228                 offset = phdr_ptr->p_offset;
229                 notes_section = kmalloc(max_sz, GFP_KERNEL);
230                 if (!notes_section)
231                         return -ENOMEM;
232                 rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
233                 if (rc < 0) {
234                         kfree(notes_section);
235                         return rc;
236                 }
237                 nhdr_ptr = notes_section;
238                 for (j = 0; j < max_sz; j += sz) {
239                         if (nhdr_ptr->n_namesz == 0)
240                                 break;
241                         sz = sizeof(Elf64_Nhdr) +
242                                 ((nhdr_ptr->n_namesz + 3) & ~3) +
243                                 ((nhdr_ptr->n_descsz + 3) & ~3);
244                         real_sz += sz;
245                         nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
246                 }
247 
248                 /* Add this contiguous chunk of notes section to vmcore list.*/
249                 new = get_new_element();
250                 if (!new) {
251                         kfree(notes_section);
252                         return -ENOMEM;
253                 }
254                 new->paddr = phdr_ptr->p_offset;
255                 new->size = real_sz;
256                 list_add_tail(&new->list, vc_list);
257                 phdr_sz += real_sz;
258                 kfree(notes_section);
259         }
260 
261         /* Prepare merged PT_NOTE program header. */
262         phdr.p_type    = PT_NOTE;
263         phdr.p_flags   = 0;
264         note_off = sizeof(Elf64_Ehdr) +
265                         (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
266         phdr.p_offset  = note_off;
267         phdr.p_vaddr   = phdr.p_paddr = 0;
268         phdr.p_filesz  = phdr.p_memsz = phdr_sz;
269         phdr.p_align   = 0;
270 
271         /* Add merged PT_NOTE program header*/
272         tmp = elfptr + sizeof(Elf64_Ehdr);
273         memcpy(tmp, &phdr, sizeof(phdr));
274         tmp += sizeof(phdr);
275 
276         /* Remove unwanted PT_NOTE program headers. */
277         i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
278         *elfsz = *elfsz - i;
279         memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
280 
281         /* Modify e_phnum to reflect merged headers. */
282         ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
283 
284         return 0;
285 }
286 
287 /* Merges all the PT_NOTE headers into one. */
288 static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
289                                                 struct list_head *vc_list)
290 {
291         int i, nr_ptnote=0, rc=0;
292         char *tmp;
293         Elf32_Ehdr *ehdr_ptr;
294         Elf32_Phdr phdr, *phdr_ptr;
295         Elf32_Nhdr *nhdr_ptr;
296         u64 phdr_sz = 0, note_off;
297 
298         ehdr_ptr = (Elf32_Ehdr *)elfptr;
299         phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
300         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
301                 int j;
302                 void *notes_section;
303                 struct vmcore *new;
304                 u64 offset, max_sz, sz, real_sz = 0;
305                 if (phdr_ptr->p_type != PT_NOTE)
306                         continue;
307                 nr_ptnote++;
308                 max_sz = phdr_ptr->p_memsz;
309                 offset = phdr_ptr->p_offset;
310                 notes_section = kmalloc(max_sz, GFP_KERNEL);
311                 if (!notes_section)
312                         return -ENOMEM;
313                 rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
314                 if (rc < 0) {
315                         kfree(notes_section);
316                         return rc;
317                 }
318                 nhdr_ptr = notes_section;
319                 for (j = 0; j < max_sz; j += sz) {
320                         if (nhdr_ptr->n_namesz == 0)
321                                 break;
322                         sz = sizeof(Elf32_Nhdr) +
323                                 ((nhdr_ptr->n_namesz + 3) & ~3) +
324                                 ((nhdr_ptr->n_descsz + 3) & ~3);
325                         real_sz += sz;
326                         nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
327                 }
328 
329                 /* Add this contiguous chunk of notes section to vmcore list.*/
330                 new = get_new_element();
331                 if (!new) {
332                         kfree(notes_section);
333                         return -ENOMEM;
334                 }
335                 new->paddr = phdr_ptr->p_offset;
336                 new->size = real_sz;
337                 list_add_tail(&new->list, vc_list);
338                 phdr_sz += real_sz;
339                 kfree(notes_section);
340         }
341 
342         /* Prepare merged PT_NOTE program header. */
343         phdr.p_type    = PT_NOTE;
344         phdr.p_flags   = 0;
345         note_off = sizeof(Elf32_Ehdr) +
346                         (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
347         phdr.p_offset  = note_off;
348         phdr.p_vaddr   = phdr.p_paddr = 0;
349         phdr.p_filesz  = phdr.p_memsz = phdr_sz;
350         phdr.p_align   = 0;
351 
352         /* Add merged PT_NOTE program header*/
353         tmp = elfptr + sizeof(Elf32_Ehdr);
354         memcpy(tmp, &phdr, sizeof(phdr));
355         tmp += sizeof(phdr);
356 
357         /* Remove unwanted PT_NOTE program headers. */
358         i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
359         *elfsz = *elfsz - i;
360         memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
361 
362         /* Modify e_phnum to reflect merged headers. */
363         ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
364 
365         return 0;
366 }
367 
368 /* Add memory chunks represented by program headers to vmcore list. Also update
369  * the new offset fields of exported program headers. */
370 static int __init process_ptload_program_headers_elf64(char *elfptr,
371                                                 size_t elfsz,
372                                                 struct list_head *vc_list)
373 {
374         int i;
375         Elf64_Ehdr *ehdr_ptr;
376         Elf64_Phdr *phdr_ptr;
377         loff_t vmcore_off;
378         struct vmcore *new;
379 
380         ehdr_ptr = (Elf64_Ehdr *)elfptr;
381         phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
382 
383         /* First program header is PT_NOTE header. */
384         vmcore_off = sizeof(Elf64_Ehdr) +
385                         (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) +
386                         phdr_ptr->p_memsz; /* Note sections */
387 
388         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
389                 if (phdr_ptr->p_type != PT_LOAD)
390                         continue;
391 
392                 /* Add this contiguous chunk of memory to vmcore list.*/
393                 new = get_new_element();
394                 if (!new)
395                         return -ENOMEM;
396                 new->paddr = phdr_ptr->p_offset;
397                 new->size = phdr_ptr->p_memsz;
398                 list_add_tail(&new->list, vc_list);
399 
400                 /* Update the program header offset. */
401                 phdr_ptr->p_offset = vmcore_off;
402                 vmcore_off = vmcore_off + phdr_ptr->p_memsz;
403         }
404         return 0;
405 }
406 
407 static int __init process_ptload_program_headers_elf32(char *elfptr,
408                                                 size_t elfsz,
409                                                 struct list_head *vc_list)
410 {
411         int i;
412         Elf32_Ehdr *ehdr_ptr;
413         Elf32_Phdr *phdr_ptr;
414         loff_t vmcore_off;
415         struct vmcore *new;
416 
417         ehdr_ptr = (Elf32_Ehdr *)elfptr;
418         phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
419 
420         /* First program header is PT_NOTE header. */
421         vmcore_off = sizeof(Elf32_Ehdr) +
422                         (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) +
423                         phdr_ptr->p_memsz; /* Note sections */
424 
425         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
426                 if (phdr_ptr->p_type != PT_LOAD)
427                         continue;
428 
429                 /* Add this contiguous chunk of memory to vmcore list.*/
430                 new = get_new_element();
431                 if (!new)
432                         return -ENOMEM;
433                 new->paddr = phdr_ptr->p_offset;
434                 new->size = phdr_ptr->p_memsz;
435                 list_add_tail(&new->list, vc_list);
436 
437                 /* Update the program header offset */
438                 phdr_ptr->p_offset = vmcore_off;
439                 vmcore_off = vmcore_off + phdr_ptr->p_memsz;
440         }
441         return 0;
442 }
443 
444 /* Sets offset fields of vmcore elements. */
445 static void __init set_vmcore_list_offsets_elf64(char *elfptr,
446                                                 struct list_head *vc_list)
447 {
448         loff_t vmcore_off;
449         Elf64_Ehdr *ehdr_ptr;
450         struct vmcore *m;
451 
452         ehdr_ptr = (Elf64_Ehdr *)elfptr;
453 
454         /* Skip Elf header and program headers. */
455         vmcore_off = sizeof(Elf64_Ehdr) +
456                         (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr);
457 
458         list_for_each_entry(m, vc_list, list) {
459                 m->offset = vmcore_off;
460                 vmcore_off += m->size;
461         }
462 }
463 
464 /* Sets offset fields of vmcore elements. */
465 static void __init set_vmcore_list_offsets_elf32(char *elfptr,
466                                                 struct list_head *vc_list)
467 {
468         loff_t vmcore_off;
469         Elf32_Ehdr *ehdr_ptr;
470         struct vmcore *m;
471 
472         ehdr_ptr = (Elf32_Ehdr *)elfptr;
473 
474         /* Skip Elf header and program headers. */
475         vmcore_off = sizeof(Elf32_Ehdr) +
476                         (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr);
477 
478         list_for_each_entry(m, vc_list, list) {
479                 m->offset = vmcore_off;
480                 vmcore_off += m->size;
481         }
482 }
483 
484 static int __init parse_crash_elf64_headers(void)
485 {
486         int rc=0;
487         Elf64_Ehdr ehdr;
488         u64 addr;
489 
490         addr = elfcorehdr_addr;
491 
492         /* Read Elf header */
493         rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
494         if (rc < 0)
495                 return rc;
496 
497         /* Do some basic Verification. */
498         if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
499                 (ehdr.e_type != ET_CORE) ||
500                 !vmcore_elf_check_arch(&ehdr) ||
501                 ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
502                 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
503                 ehdr.e_version != EV_CURRENT ||
504                 ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
505                 ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
506                 ehdr.e_phnum == 0) {
507                 printk(KERN_WARNING "Warning: Core image elf header is not"
508                                         "sane\n");
509                 return -EINVAL;
510         }
511 
512         /* Read in all elf headers. */
513         elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
514         elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
515         if (!elfcorebuf)
516                 return -ENOMEM;
517         addr = elfcorehdr_addr;
518         rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
519         if (rc < 0) {
520                 kfree(elfcorebuf);
521                 return rc;
522         }
523 
524         /* Merge all PT_NOTE headers into one. */
525         rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
526         if (rc) {
527                 kfree(elfcorebuf);
528                 return rc;
529         }
530         rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
531                                                         &vmcore_list);
532         if (rc) {
533                 kfree(elfcorebuf);
534                 return rc;
535         }
536         set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list);
537         return 0;
538 }
539 
540 static int __init parse_crash_elf32_headers(void)
541 {
542         int rc=0;
543         Elf32_Ehdr ehdr;
544         u64 addr;
545 
546         addr = elfcorehdr_addr;
547 
548         /* Read Elf header */
549         rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
550         if (rc < 0)
551                 return rc;
552 
553         /* Do some basic Verification. */
554         if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
555                 (ehdr.e_type != ET_CORE) ||
556                 !elf_check_arch(&ehdr) ||
557                 ehdr.e_ident[EI_CLASS] != ELFCLASS32||
558                 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
559                 ehdr.e_version != EV_CURRENT ||
560                 ehdr.e_ehsize != sizeof(Elf32_Ehdr) ||
561                 ehdr.e_phentsize != sizeof(Elf32_Phdr) ||
562                 ehdr.e_phnum == 0) {
563                 printk(KERN_WARNING "Warning: Core image elf header is not"
564                                         "sane\n");
565                 return -EINVAL;
566         }
567 
568         /* Read in all elf headers. */
569         elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
570         elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
571         if (!elfcorebuf)
572                 return -ENOMEM;
573         addr = elfcorehdr_addr;
574         rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
575         if (rc < 0) {
576                 kfree(elfcorebuf);
577                 return rc;
578         }
579 
580         /* Merge all PT_NOTE headers into one. */
581         rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
582         if (rc) {
583                 kfree(elfcorebuf);
584                 return rc;
585         }
586         rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
587                                                                 &vmcore_list);
588         if (rc) {
589                 kfree(elfcorebuf);
590                 return rc;
591         }
592         set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list);
593         return 0;
594 }
595 
596 static int __init parse_crash_elf_headers(void)
597 {
598         unsigned char e_ident[EI_NIDENT];
599         u64 addr;
600         int rc=0;
601 
602         addr = elfcorehdr_addr;
603         rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
604         if (rc < 0)
605                 return rc;
606         if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
607                 printk(KERN_WARNING "Warning: Core image elf header"
608                                         " not found\n");
609                 return -EINVAL;
610         }
611 
612         if (e_ident[EI_CLASS] == ELFCLASS64) {
613                 rc = parse_crash_elf64_headers();
614                 if (rc)
615                         return rc;
616 
617                 /* Determine vmcore size. */
618                 vmcore_size = get_vmcore_size_elf64(elfcorebuf);
619         } else if (e_ident[EI_CLASS] == ELFCLASS32) {
620                 rc = parse_crash_elf32_headers();
621                 if (rc)
622                         return rc;
623 
624                 /* Determine vmcore size. */
625                 vmcore_size = get_vmcore_size_elf32(elfcorebuf);
626         } else {
627                 printk(KERN_WARNING "Warning: Core image elf header is not"
628                                         " sane\n");
629                 return -EINVAL;
630         }
631         return 0;
632 }
633 
634 /* Init function for vmcore module. */
635 static int __init vmcore_init(void)
636 {
637         int rc = 0;
638 
639         /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
640         if (!(is_vmcore_usable()))
641                 return rc;
642         rc = parse_crash_elf_headers();
643         if (rc) {
644                 printk(KERN_WARNING "Kdump: vmcore not initialized\n");
645                 return rc;
646         }
647 
648         proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
649         if (proc_vmcore)
650                 proc_vmcore->size = vmcore_size;
651         return 0;
652 }
653 module_init(vmcore_init)
654 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp