Re: dilemma: /proc/kcore vs (x)kdebug.

David Howells (David.Howells@nexor.co.uk)
Thu, 01 Apr 1999 09:05:06 BST


Tigran Aivazian wrote:
> 3. Use what all good Linux books recommend: compile with -g and then do
> gdb vmlinux /proc/kcore.
> (does not work, try it and see).

I've got a patch which fixes this problem (which I've posted before)... It
makes /proc/kcore an ELF core dump instead of an aout core dump.

All the best,
David Howells

=============
diff -uNr linux-2.2.1/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-2.2.1/fs/proc/Makefile Wed Jun 24 22:30:10 1998
+++ linux/fs/proc/Makefile Tue Mar 2 07:56:38 1999
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.

O_TARGET := proc.o
-O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
+O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o kcore.o \
kmsg.o scsi.o proc_tty.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
diff -uNr linux-2.2.1/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.1/fs/proc/array.c Thu Jan 28 18:08:53 1999
+++ linux/fs/proc/array.c Tue Mar 2 07:57:31 1999
@@ -75,74 +75,6 @@
int get_malloc(char * buffer);
#endif

-
-static ssize_t read_core(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos, memsize;
- ssize_t read;
- ssize_t count1;
- char * pnt;
- struct user dump;
-#if defined (__i386__) || defined (__mc68000__)
-# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
-#else
-# define FIRST_MAPPED 0
-#endif
-
- memset(&dump, 0, sizeof(struct user));
- dump.magic = CMAGIC;
- dump.u_dsize = max_mapnr;
-#ifdef __alpha__
- dump.start_data = PAGE_OFFSET;
-#endif
-
- memsize = (max_mapnr + 1) << PAGE_SHIFT;
- if (p >= memsize)
- return 0;
- if (count > memsize - p)
- count = memsize - p;
- read = 0;
-
- if (p < sizeof(struct user) && count > 0) {
- count1 = count;
- if (p + count1 > sizeof(struct user))
- count1 = sizeof(struct user)-p;
- pnt = (char *) &dump + p;
- copy_to_user(buf,(void *) pnt, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
-
- if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
- count1 = PAGE_SIZE + FIRST_MAPPED - p;
- if (count1 > count)
- count1 = count;
- clear_user(buf, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
- if (count > 0) {
- copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
- read += count;
- }
- *ppos += read;
- return read;
-}
-
-static struct file_operations proc_kcore_operations = {
- NULL, /* lseek */
- read_core,
-};
-
-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
diff -uNr linux-2.2.1/fs/proc/kcore.c linux/fs/proc/kcore.c
--- linux-2.2.1/fs/proc/kcore.c Thu Jan 1 01:00:00 1970
+++ linux/fs/proc/kcore.c Tue Mar 2 08:03:17 1999
@@ -0,0 +1,313 @@
+/*
+ * kernel ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <asm/uaccess.h>
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+ const char *name;
+ int type;
+ unsigned int datasz;
+ void *data;
+};
+
+static char saved_command_line[] =
+ "vmlinux BOOT_IMAGE=bus ro root=303 mem=127M";
+
+/*****************************************************************************/
+/*
+ * determine size of ELF note
+ */
+static int notesize(struct memelfnote *en)
+{
+ int sz;
+
+ sz = sizeof(struct elf_note);
+ sz += roundup(strlen(en->name), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+} /* end notesize() */
+
+/*****************************************************************************/
+/*
+ * store a note in the header buffer
+ */
+static char *storenote(struct memelfnote *men, char *bufp)
+{
+ struct elf_note en;
+
+#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
+
+ en.n_namesz = strlen(men->name);
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+ DUMP_WRITE(&en, sizeof(en));
+ DUMP_WRITE(men->name, en.n_namesz);
+
+ /* XXX - cast from long long to long to avoid need for libgcc.a */
+ bufp = (char*) roundup((unsigned long)bufp,4);
+ DUMP_WRITE(men->data, men->datasz);
+ bufp = (char*) roundup((unsigned long)bufp,4);
+
+#undef DUMP_WRITE
+
+ return bufp;
+} /* end storenote() */
+
+/*****************************************************************************/
+/*
+ * store an ELF coredump header in the supplied buffer
+ * - assume the memory image is the size specified
+ */
+static void elf_kcore_store_hdr(char *bufp, size_t size, off_t dataoff)
+{
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
+ struct elf_phdr *nhdr, *dhdr;
+ struct elfhdr *elf;
+ struct memelfnote notes[3];
+ off_t offset = 0;
+
+ /* acquire an ELF header block from the buffer */
+ elf = (struct elfhdr *) bufp;
+ bufp += sizeof(*elf);
+ offset += sizeof(*elf);
+
+ /* set up header */
+ 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;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(*elf);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(*elf);
+ elf->e_phentsize= sizeof(struct elf_phdr);
+ elf->e_phnum = 2; /* no. of segments */
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* acquire an ELF program header blocks from the buffer for notes */
+ nhdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(*nhdr);
+ offset += sizeof(*nhdr);
+
+ /* store program headers for notes dump */
+ nhdr->p_type = PT_NOTE;
+ nhdr->p_offset = 0;
+ nhdr->p_vaddr = 0;
+ nhdr->p_paddr = 0;
+ nhdr->p_memsz = 0;
+ nhdr->p_flags = 0;
+ nhdr->p_align = 0;
+
+ /* acquire an ELF program header blocks from the buffer for data */
+ dhdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(*dhdr);
+ offset += sizeof(*dhdr);
+
+ /* store program headers for data dump */
+ dhdr->p_type = PT_LOAD;
+ dhdr->p_flags = PF_R|PF_W|PF_X;
+ dhdr->p_offset = dataoff;
+ dhdr->p_vaddr = PAGE_OFFSET;
+ dhdr->p_paddr = __pa(PAGE_OFFSET);
+ dhdr->p_filesz = size;
+ dhdr->p_memsz = size;
+ dhdr->p_align = PAGE_SIZE;
+
+ /*
+ * Set up the notes in similar form to SVR4 core dumps made
+ * with info from their /proc.
+ */
+ nhdr->p_offset = offset;
+ nhdr->p_filesz = 0;
+
+ /* set up the process status */
+ notes[0].name = "CORE";
+ notes[0].type = NT_PRSTATUS;
+ notes[0].datasz = sizeof(prstatus);
+ notes[0].data = &prstatus;
+
+ memset(&prstatus,0,sizeof(prstatus));
+
+ nhdr->p_filesz = notesize(&notes[0]);
+ bufp = storenote(&notes[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;
+
+ memset(&psinfo,0,sizeof(psinfo));
+ psinfo.pr_state = 0;
+ psinfo.pr_sname = 'R';
+ psinfo.pr_zomb = 0;
+
+ strcpy(psinfo.pr_fname,"vmlinux");
+ strncpy(psinfo.pr_psargs,saved_command_line,ELF_PRARGSZ);
+
+ nhdr->p_filesz = notesize(&notes[1]);
+ bufp = storenote(&notes[1],bufp);
+
+ /* set up the task structure */
+ notes[2].name = "CORE";
+ notes[2].type = NT_TASKSTRUCT;
+ notes[2].datasz = sizeof(*current);
+ notes[2].data = current;
+
+ nhdr->p_filesz = notesize(&notes[2]);
+ bufp = storenote(&notes[2],bufp);
+
+} /* end elf_kcore_store_hdr() */
+
+/*****************************************************************************/
+/*
+ * read from the ELF header and then kernel memory
+ */
+static ssize_t elf_kcore_read(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 */
+ size = ((size_t)high_memory - PAGE_OFFSET) + PAGE_SIZE;
+ acc = 0;
+
+ /* see if file pointer already beyond EOF */
+ if (buflen==0 || *fpos>=size)
+ return 0;
+
+ /* trim buflen to not go beyond EOF */
+ if (buflen > size-*fpos)
+ buflen = size - *fpos;
+
+ /* construct an ELF core header if we'll need some of it */
+ if (*fpos<PAGE_SIZE) {
+ /* get a buffer */
+ page = (char*) __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ tsz = PAGE_SIZE-*fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+
+ /* create a header */
+ memset(page,0,PAGE_SIZE);
+ elf_kcore_store_hdr(page,size-PAGE_SIZE,PAGE_SIZE);
+
+ /* copy data to the users buffer */
+ copy_to_user(buffer,page,tsz);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ free_page((unsigned long) page);
+
+ /* leave now if filled buffer already */
+ if (buflen==0)
+ return tsz;
+ }
+
+ /* where page 0 not mapped, write zeros into buffer */
+#if defined (__i386__) || defined (__mc68000__)
+ if (*fpos < PAGE_SIZE*2) {
+ /* work out how much to clear */
+ tsz = PAGE_SIZE*2 - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+
+ /* write zeros to buffer */
+ clear_user(buffer,tsz);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen==0)
+ return tsz;
+ }
+#endif
+
+ /* fill the remainder of the buffer from kernel VM space */
+#if defined (__i386__) || defined (__mc68000__)
+ copy_to_user(buffer,__va(*fpos-PAGE_SIZE),buflen);
+#else
+ copy_to_user(buffer,__va(*fpos),buflen);
+#endif
+ acc += buflen;
+
+ return acc;
+
+} /* end elf_kcore_read() */
+
+/*****************************************************************************/
+/*
+ * stop the module being unloaded when the file is open
+ */
+static int elf_kcore_open(struct inode *inode, struct file *file)
+{
+ MOD_INC_USE_COUNT;
+
+ return 0;
+} /* end elf_kcore_open() */
+
+/*****************************************************************************/
+/*
+ * allow the module to be unloaded again
+ */
+static int elf_kcore_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+} /* end elf_kcore_release() */
+
+/*****************************************************************************/
+/*
+ * /proc interface
+ */
+static struct file_operations elf_kcore_operations = {
+ NULL, /* lseek */
+ elf_kcore_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ elf_kcore_open, /* open */
+ NULL, /* flush */
+ elf_kcore_release /* release */
+};
+
+struct inode_operations proc_kcore_inode_operations = {
+ &elf_kcore_operations,
+};

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/