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