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