diff -urN -X dontdiff linux/fs/proc/kcore.c 2327-p6-kcore/fs/proc/kcore.c --- linux/fs/proc/kcore.c Thu Nov 11 08:58:59 1999 +++ 2327-p6-kcore/fs/proc/kcore.c Thu Nov 11 16:17:50 1999 @@ -5,7 +5,7 @@ * Jeremy Fitzhardinge * Implemented by David Howells * Modified and incorporated into 2.3.x by Tigran Aivazian - * Support to dump module's data structures (ELF only), Tigran Aivazian + * Support to dump vmalloc'd data structures (ELF only), Tigran Aivazian */ #include @@ -15,13 +15,35 @@ #include #include #include -#include -#include - +#include +#include #include + +static int open_kcore(struct inode * inode, struct file * filp) +{ + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +} + +static ssize_t read_kcore(struct file *, char *, size_t, loff_t *); + +static struct file_operations proc_kcore_operations = { + NULL, /* lseek */ + read_kcore, + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + open_kcore +}; + +struct inode_operations proc_kcore_inode_operations = { + &proc_kcore_operations, +}; + #ifdef CONFIG_KCORE_AOUT -ssize_t read_kcore(struct file * file, char * buf, +static ssize_t read_kcore(struct file * file, char * buf, size_t count, loff_t *ppos) { unsigned long long p = *ppos, memsize; @@ -81,8 +103,7 @@ *ppos += read; return read; } -#else - +#else /* CONFIG_KCORE_AOUT */ #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) @@ -97,6 +118,31 @@ extern char saved_command_line[]; +static size_t get_kcore_size(int *num_vma, size_t *elf_buflen) +{ + size_t try, size = 0; + struct vm_struct *m; + + *num_vma = 0; + if (!vmlist) { + *elf_buflen = PAGE_SIZE; + return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE); + } + + for (m=vmlist; m; m=m->next) { + try = (size_t)m->addr + m->size; + if (try > size) + size = try; + *num_vma = *num_vma + 1; + } + *elf_buflen = sizeof(struct elfhdr) + + (*num_vma + 2)*sizeof(struct elf_phdr) + + 3 * sizeof(struct memelfnote); + *elf_buflen = PAGE_ALIGN(*elf_buflen); + return (size - PAGE_OFFSET + *elf_buflen); +} + + /*****************************************************************************/ /* * determine size of ELF note @@ -139,32 +185,29 @@ return bufp; } /* end storenote() */ -/*****************************************************************************/ /* * store an ELF coredump header in the supplied buffer - * - assume the memory image is the size specified + * num_vma is the number of elements in vmlist */ -static void elf_kcore_store_hdr(char *bufp) +static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) { struct elf_prstatus prstatus; /* NT_PRSTATUS */ - struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - struct elf_phdr *nhdr, *dhdr; + struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */ + struct elf_phdr *nhdr, *phdr; struct elfhdr *elf; struct memelfnote notes[3]; off_t offset = 0; + struct vm_struct *m; - /* acquire an ELF header block from the buffer */ + /* setup ELF header */ elf = (struct elfhdr *) bufp; bufp += sizeof(struct elfhdr); offset += sizeof(struct elfhdr); - - /* set up header */ - memcpy(elf->e_ident,ELFMAG,SELFMAG); + memcpy(elf->e_ident, ELFMAG, SELFMAG); elf->e_ident[EI_CLASS] = ELF_CLASS; elf->e_ident[EI_DATA] = ELF_DATA; elf->e_ident[EI_VERSION]= EV_CURRENT; memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - elf->e_type = ET_CORE; elf->e_machine = ELF_ARCH; elf->e_version = EV_CURRENT; @@ -174,17 +217,15 @@ elf->e_flags = 0; elf->e_ehsize = sizeof(struct elfhdr); elf->e_phentsize= sizeof(struct elf_phdr); - elf->e_phnum = 1; /* no. of segments = 1 + Nmodules */ + elf->e_phnum = 2 + num_vma; elf->e_shentsize= 0; elf->e_shnum = 0; elf->e_shstrndx = 0; - /* acquire an ELF program header blocks from the buffer for notes */ + /* setup ELF PT_NOTE program header */ nhdr = (struct elf_phdr *) bufp; bufp += sizeof(struct elf_phdr); offset += sizeof(struct elf_phdr); - - /* store program headers for notes dump */ nhdr->p_type = PT_NOTE; nhdr->p_offset = 0; nhdr->p_vaddr = 0; @@ -194,43 +235,33 @@ nhdr->p_flags = 0; nhdr->p_align = 0; - /* acquire an ELF program header blocks from the buffer for data */ - dhdr = (struct elf_phdr *) bufp; + /* setup ELF PT_LOAD program header for the + * virtual range 0xc0000000->high_memory */ + phdr = (struct elf_phdr *) bufp; bufp += sizeof(struct elf_phdr); offset += sizeof(struct elf_phdr); - - /* store program headers for data dump */ - dhdr->p_type = PT_LOAD; - dhdr->p_flags = PF_R|PF_W|PF_X; - dhdr->p_offset = PAGE_SIZE; - dhdr->p_vaddr = PAGE_OFFSET; - dhdr->p_paddr = __pa(PAGE_OFFSET); - dhdr->p_filesz = ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE); - dhdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE); - dhdr->p_align = PAGE_SIZE; - -#ifdef CONFIG_MODULES - { - struct module *m; - lock_kernel(); - for (m=module_list; m; m=m->next) { - dhdr = (struct elf_phdr *) bufp; - bufp += sizeof(struct elf_phdr); - offset += sizeof(struct elf_phdr); - - dhdr->p_type = PT_LOAD; - dhdr->p_flags = PF_R|PF_W|PF_X; - dhdr->p_offset = (unsigned long)m - PAGE_OFFSET + PAGE_SIZE; - dhdr->p_vaddr = (unsigned long)m; - dhdr->p_paddr = __pa(m); - dhdr->p_filesz = m->size; - dhdr->p_memsz = m->size; - dhdr->p_align = 0; - elf->e_phnum++; - } - lock_kernel(); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = dataoff; + phdr->p_vaddr = PAGE_OFFSET; + phdr->p_paddr = __pa(PAGE_OFFSET); + phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET); + phdr->p_align = PAGE_SIZE; + + /* setup ELF PT_LOAD program headers, one for each kvma range */ + for (m=vmlist; m; m=m->next) { + phdr = (struct elf_phdr *) bufp; + bufp += sizeof(struct elf_phdr); + offset += sizeof(struct elf_phdr); + + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = (size_t)m->addr - PAGE_OFFSET + dataoff; + phdr->p_vaddr = (size_t)m->addr; + phdr->p_paddr = __pa(m->addr); + phdr->p_filesz = phdr->p_memsz = m->size; + phdr->p_align = PAGE_SIZE; } -#endif /* * Set up the notes in similar form to SVR4 core dumps made @@ -241,39 +272,39 @@ /* set up the process status */ notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; - notes[0].datasz = sizeof(prstatus); + notes[0].datasz = sizeof(struct elf_prstatus); notes[0].data = &prstatus; - memset(&prstatus,0,sizeof(prstatus)); + memset(&prstatus, 0, sizeof(struct elf_prstatus)); nhdr->p_filesz = notesize(¬es[0]); - bufp = storenote(¬es[0],bufp); + bufp = storenote(¬es[0], bufp); /* set up the process info */ notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; - notes[1].datasz = sizeof(psinfo); - notes[1].data = &psinfo; + notes[1].datasz = sizeof(struct elf_prpsinfo); + notes[1].data = &prpsinfo; - memset(&psinfo,0,sizeof(psinfo)); - psinfo.pr_state = 0; - psinfo.pr_sname = 'R'; - psinfo.pr_zomb = 0; + memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo)); + prpsinfo.pr_state = 0; + prpsinfo.pr_sname = 'R'; + prpsinfo.pr_zomb = 0; - strcpy(psinfo.pr_fname,"vmlinux"); - strncpy(psinfo.pr_psargs,saved_command_line,ELF_PRARGSZ); + strcpy(prpsinfo.pr_fname, "vmlinux"); + strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ); nhdr->p_filesz = notesize(¬es[1]); - bufp = storenote(¬es[1],bufp); + bufp = storenote(¬es[1], bufp); /* set up the task structure */ notes[2].name = "CORE"; notes[2].type = NT_TASKSTRUCT; - notes[2].datasz = sizeof(*current); + notes[2].datasz = sizeof(struct task_struct); notes[2].data = current; nhdr->p_filesz = notesize(¬es[2]); - bufp = storenote(¬es[2],bufp); + bufp = storenote(¬es[2], bufp); } /* end elf_kcore_store_hdr() */ @@ -281,85 +312,75 @@ /* * read from the ELF header and then kernel memory */ -ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, +static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t *fpos) { - ssize_t acc; - size_t size, tsz; - char *page; - - /* work out how much file we allow to be read */ - proc_root_kcore.size = size = get_kcore_size(); - acc = 0; - - /* see if file pointer already beyond EOF */ - if (buflen==0 || *fpos>=size) + ssize_t acc = 0; + size_t size, tsz = 0; + char * elf_buffer; + size_t elf_buflen = 0; + int num_vma = 0; + + /* XXX we need to somehow lock vmlist between here + * and after elf_kcore_store_hdr() returns. + * For now assume that num_vma does not change (TA) + */ + proc_root_kcore.size = size = get_kcore_size(&num_vma, &elf_buflen); + if (buflen == 0 || *fpos >= size) return 0; /* trim buflen to not go beyond EOF */ - if (buflen > size-*fpos) + if (buflen > size - *fpos) buflen = size - *fpos; /* construct an ELF core header if we'll need some of it */ - if (*fpos #include #include -#include -#include #include #include #include @@ -546,28 +544,6 @@ return len; } -static int open_kcore(struct inode * inode, struct file * filp) -{ - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; -} - -extern ssize_t read_kcore(struct file *, char *, size_t, loff_t *); - -static struct file_operations proc_kcore_operations = { - NULL, /* lseek */ - read_kcore, - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - open_kcore -}; - -static struct inode_operations proc_kcore_inode_operations = { - &proc_kcore_operations, -}; - /* * This function accesses profiling information. The returned data is * binary: the sampling step and the actual contents of the profile @@ -704,7 +680,7 @@ /* And now for trickier ones */ proc_register(&proc_root, &proc_root_kmsg); proc_register(&proc_root, &proc_root_kcore); - proc_root_kcore.size = get_kcore_size(); + proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; if (prof_shift) { proc_register(&proc_root, &proc_root_profile); proc_root_profile.size = (1+prof_len) * sizeof(unsigned int); diff -urN -X dontdiff linux/include/linux/module.h 2327-p6-kcore/include/linux/module.h --- linux/include/linux/module.h Thu Nov 11 08:59:03 1999 +++ 2327-p6-kcore/include/linux/module.h Thu Nov 11 11:57:16 1999 @@ -287,5 +287,4 @@ #define EXPORT_NO_SYMBOLS #endif /* MODULE */ -extern unsigned long get_kcore_size(void); #endif /* _LINUX_MODULE_H */ diff -urN -X dontdiff linux/include/linux/vmalloc.h 2327-p6-kcore/include/linux/vmalloc.h --- linux/include/linux/vmalloc.h Sun Nov 7 03:06:22 1999 +++ 2327-p6-kcore/include/linux/vmalloc.h Thu Nov 11 09:06:13 1999 @@ -20,5 +20,6 @@ void vmfree_area_pages(unsigned long address, unsigned long size); int vmalloc_area_pages(unsigned long address, unsigned long size); +extern struct vm_struct * vmlist; #endif diff -urN -X dontdiff linux/kernel/module.c 2327-p6-kcore/kernel/module.c --- linux/kernel/module.c Thu Nov 11 08:59:04 1999 +++ 2327-p6-kcore/kernel/module.c Thu Nov 11 09:01:01 1999 @@ -53,25 +53,6 @@ static void free_module(struct module *, int tag_freed); -/* needed for /proc/kcore, here because kernel_module is static (TA) */ -unsigned long get_kcore_size(void) -{ - unsigned long try, size = 0; - struct module * m; - - if (module_list == &kernel_module) - return ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE); - - lock_kernel(); - for (m=module_list; m; m=m->next) { - try = (unsigned long)m + m->size; - if (try > size) - size = try; - } - unlock_kernel(); - return (size - PAGE_OFFSET + PAGE_SIZE); -} - /* * Called at boot time */ @@ -987,13 +968,6 @@ } #else /* CONFIG_MODULES */ - -/* no MODULES so high_memory is good enough for /proc/kcore (TA) */ -unsigned long get_kcore_size(void) -{ - return ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE); -} - /* Dummy syscalls for people who don't want modules */ diff -urN -X dontdiff linux/mm/vmalloc.c 2327-p6-kcore/mm/vmalloc.c --- linux/mm/vmalloc.c Thu Nov 11 08:59:05 1999 +++ 2327-p6-kcore/mm/vmalloc.c Thu Nov 11 09:01:01 1999 @@ -10,7 +10,7 @@ #include -static struct vm_struct * vmlist = NULL; +struct vm_struct * vmlist = NULL; static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) { .