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