netns xfrm: fix "ip xfrm state|policy count" misreport
[safe/jmp/linux-2.6] / fs / proc / vmcore.c
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)