Parse elf32 headers and export through /proc/vmcore
Subsystems (2)
PATCH 15/17 Parse elf32 headers and export through /proc/vmcore
From: "Vivek Goyal" <[email protected]>
o Adds support for parsing core ELF32 headers.
o I am expecting ELF32 support to go away down the line. This patch has been introduced for testing purposes as gdb can not parse ELF64 headers for i386. When a decent user space solution is available, ELF32 support can go away.
Signed-off-by Vivek Goyal <[email protected]>
---
linux-2.6.12-rc1-mm1-16M-root/fs/proc/vmcore.c | 218 +++++++++++++++++++++++++ 1 files changed, 218 insertions(+)
fs/proc/vmcore.c renamed from fs/proc/vmcore.c~crashdump-parse-core-elf32-headers +218 -0
@@ -202,6 +202,23 @@ static u64 __init get_vmcore_size_elf64(return size; } +static u64 __init get_vmcore_size_elf32 (char *elfptr) +{ +int i; +u64 size; +Elf32_Ehdr *ehdr_ptr; +Elf32_Phdr *phdr_ptr; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr *)(elfptr +sizeof (Elf32_Ehdr)); + size =sizeof (Elf32_Ehdr) + ((ehdr_ptr->e_phnum) *sizeof (Elf32_Phdr)); +for (i =0 ; i < ehdr_ptr->e_phnum; i++) { + size += phdr_ptr->p_memsz; + phdr_ptr++; + } +return size; +} +/* Merges all the PT_NOTE headers into one. */ static int __init merge_note_headers_elf64 (char *elfptr,size_t *elfsz,struct list_head *vc_list)
@@ -283,6 +300,87 @@ static int __init merge_note_headers_elfreturn 0 ; } +/* Merges all the PT_NOTE headers into one. */ +static int __init merge_note_headers_elf32 (char *elfptr,size_t *elfsz, +struct list_head *vc_list) +{ +int i, nr_ptnote=0 , rc=0 ; +char *tmp; +Elf32_Ehdr *ehdr_ptr; +Elf32_Phdr phdr, *phdr_ptr; +Elf32_Nhdr *nhdr_ptr; +u64 phdr_sz =0 , note_off; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr *)(elfptr +sizeof (Elf32_Ehdr)); +for (i =0 ; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { +int j; +void *notes_section; +struct vmcore *new; +u64 offset, max_sz, sz, real_sz =0 ; +if (phdr_ptr->p_type !=PT_NOTE ) +continue ; + nr_ptnote++; + max_sz = phdr_ptr->p_memsz; + offset = phdr_ptr->p_offset; + notes_section =kmalloc (max_sz,GFP_KERNEL ); +if (!notes_section) +return -ENOMEM ; + rc =read_from_oldmem (notes_section, max_sz, &offset,0 ); +if (rc <0 ) { +kfree (notes_section); +return rc; + } + nhdr_ptr = notes_section; +for (j =0 ; j < max_sz; j += sz) { +if (nhdr_ptr->n_namesz ==0 ) +break ; + sz =sizeof (Elf32_Nhdr) + + ((nhdr_ptr->n_namesz +3 ) & ~3 ) + + ((nhdr_ptr->n_descsz +3 ) & ~3 ); + real_sz += sz; + nhdr_ptr = (Elf32_Nhdr *)((char *)nhdr_ptr + sz); + } + +/* Add this contiguous chunk of notes section to vmcore list.*/ + new =get_new_element (); +if (!new) { +kfree (notes_section); +return -ENOMEM ; + } + new->paddr = phdr_ptr->p_offset; + new->size = real_sz; +list_add_tail (&new->list, vc_list); + phdr_sz += real_sz; +kfree (notes_section); + } + +/* Prepare merged PT_NOTE program header. */ + phdr.p_type =PT_NOTE ; + phdr.p_flags =0 ; + note_off =sizeof (Elf32_Ehdr) + + (ehdr_ptr->e_phnum - nr_ptnote +1 ) *sizeof (Elf32_Phdr); + phdr.p_offset = note_off; + phdr.p_vaddr = phdr.p_paddr =0 ; + phdr.p_filesz = phdr.p_memsz = phdr_sz; + phdr.p_align =0 ; + +/* Add merged PT_NOTE program header*/ + tmp = elfptr +sizeof (Elf32_Ehdr); +memcpy (tmp, &phdr,sizeof (phdr)); + tmp +=sizeof (phdr); + +/* Remove unwanted PT_NOTE program headers. */ + i = (nr_ptnote -1 ) *sizeof (Elf32_Phdr); + *elfsz = *elfsz - i; +memmove (tmp, tmp+i, ((*elfsz)-sizeof (Elf32_Ehdr)-sizeof (Elf32_Phdr))); + +/* Modify e_phnum to reflect merged headers. */ + ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote +1 ; + +return 0 ; +} +/* Add memory chunks represented by program headers to vmcore list. Also update * the new offset fields of exported program headers. */ static int __init process_ptload_program_headers_elf64(char *elfptr,
@@ -322,6 +420,43 @@ static int __init process_ptload_programreturn 0 ; } +static int __init process_ptload_program_headers_elf32 (char *elfptr, +size_t elfsz, +struct list_head *vc_list) +{ +int i; +Elf32_Ehdr *ehdr_ptr; +Elf32_Phdr *phdr_ptr; +loff_t vmcore_off; +struct vmcore *new; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr *)(elfptr +sizeof (Elf32_Ehdr));/* PT_NOTE hdr */ + +/* First program header is PT_NOTE header. */ + vmcore_off =sizeof (Elf32_Ehdr) + + (ehdr_ptr->e_phnum) *sizeof (Elf32_Phdr) + + phdr_ptr->p_memsz;/* Note sections */ + +for (i =0 ; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { +if (phdr_ptr->p_type !=PT_LOAD ) +continue ; + +/* Add this contiguous chunk of memory to vmcore list.*/ + new =get_new_element (); +if (!new) +return -ENOMEM ; + new->paddr = phdr_ptr->p_offset; + new->size = phdr_ptr->p_memsz; +list_add_tail (&new->list, vc_list); + +/* Update the program header offset */ + phdr_ptr->p_offset = vmcore_off; + vmcore_off = vmcore_off + phdr_ptr->p_memsz; + } +return 0 ; +} +/* Sets offset fields of vmcore elements. */ static void __init set_vmcore_list_offsets_elf64 (char *elfptr,struct list_head *vc_list)
@@ -342,6 +477,26 @@ static void __init set_vmcore_list_offse } } +/* Sets offset fields of vmcore elements. */ +static void __init set_vmcore_list_offsets_elf32 (char *elfptr, +struct list_head *vc_list) +{ +loff_t vmcore_off; +Elf32_Ehdr *ehdr_ptr; +struct vmcore *m; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + +/* Skip Elf header and program headers. */ + vmcore_off =sizeof (Elf32_Ehdr) + + (ehdr_ptr->e_phnum) *sizeof (Elf32_Phdr); + +list_for_each_entry (m, vc_list, list) { + m->offset = vmcore_off; + vmcore_off += m->size; + } +} +static int __init parse_crash_elf64_headers (void ) {int rc=0 ;
@@ -398,6 +553,62 @@ static int __init parse_crash_elf64_headreturn 0 ; } +static int __init parse_crash_elf32_headers (void ) +{ +int rc=0 ; +Elf32_Ehdr ehdr; +u64 addr; + + addr = elfcorehdr_addr; + +/* Read Elf header */ + rc =read_from_oldmem ((char *)&ehdr,sizeof (Elf32_Ehdr), &addr,0 ); +if (rc <0 ) +return rc; + +/* Do some basic Verification. */ +if (memcmp (ehdr.e_ident,ELFMAG ,SELFMAG ) !=0 || + (ehdr.e_type !=ET_CORE ) || + !elf_check_arch (&ehdr) || + ehdr.e_ident[EI_CLASS ] !=ELFCLASS32 || + ehdr.e_ident[EI_VERSION ] !=EV_CURRENT || + ehdr.e_version !=EV_CURRENT || + ehdr.e_ehsize !=sizeof (Elf32_Ehdr) || + ehdr.e_phentsize !=sizeof (Elf32_Phdr) || + ehdr.e_phnum ==0 ) { +printk (KERN_WARNING "Warning: Core image elf header is not" +"sane\n" ); +return -EINVAL ; + } + +/* Read in all elf headers. */ + elfcorebuf_sz =sizeof (Elf32_Ehdr) + ehdr.e_phnum *sizeof (Elf32_Phdr); + elfcorebuf =kmalloc (elfcorebuf_sz,GFP_KERNEL ); +if (!elfcorebuf) +return -ENOMEM ; + addr = elfcorehdr_addr; + rc =read_from_oldmem (elfcorebuf, elfcorebuf_sz, &addr,0 ); +if (rc <0 ) { +kfree (elfcorebuf); +return rc; + } + +/* Merge all PT_NOTE headers into one. */ + rc =merge_note_headers_elf32 (elfcorebuf, &elfcorebuf_sz, &vmcore_list); +if (rc) { +kfree (elfcorebuf); +return rc; + } + rc =process_ptload_program_headers_elf32 (elfcorebuf, elfcorebuf_sz, + &vmcore_list); +if (rc) { +kfree (elfcorebuf); +return rc; + } +set_vmcore_list_offsets_elf32 (elfcorebuf, &vmcore_list); +return 0 ; +} +static int __init parse_crash_elf_headers (void ) {unsigned char e_ident[EI_NIDENT ];
@@ -421,6 +632,13 @@ static int __init parse_crash_elf_header/* Determine vmcore size. */ vmcore_size =get_vmcore_size_elf64 (elfcorebuf); + }else if (e_ident[EI_CLASS ] ==ELFCLASS32 ) { + rc =parse_crash_elf32_headers (); +if (rc) +return rc; + +/* Determine vmcore size. */ + vmcore_size =get_vmcore_size_elf32 (elfcorebuf); }else {printk (KERN_WARNING "Warning: Core image elf header is not" " sane\n" );
_