This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: /proc/kcore_elf


Dear all,

We've found a problem when using egcs to compile the Linux kernel with
debugging information compiled in (using the "-g" flag). We're doing this so
that we can attach to it with gdb whilst it is running and browse various data
structures.

We've found that the debugging information is invalid/incomplete in some
areas:

	(gdb) p task
	$1 = 0xc01f2000
	(gdb) p task[0]
	cannot subscript something of type `<data variable, no debug info>'

I've produced a kernel patch (attached) and it has been debugged by myself and
others to add a new proc file ("/proc/kcore_elf") that gives the appearance of
an ELF core dump. This alleviates much of the problem we were having, thus
allowing the presence and addresses of all variables to be correctly
determined. However, the debugging information does not appear to correctly
record the type of all these variables. Note that in the above example, the
type of task[0] is actually present, and the variable can be cast to it and
have its contents successfully read.

Tigran Aivazian writes:
> Good news! It was an egcs/gdb issue - everything works brilliantly on my
> old Red Hat 5.1 with gcc 2.7.2.3. However, many people use egcs so if we
> just replace a working (but useless because it is aout) /proc/kcore with
> half-working (because of buggy egcs) ELF /proc/kcore the "masses" will
> complain loudly. So, what I have done is added a PROC_KCORE_ELF inode with
> name /proc/kcore_elf retaining the old /proc/kcore (with aout
> read_core()).

Many Thanks,
David Howells

======================================================================
diff -urN linux/fs/proc/Makefile linux-2.2.5-elf-kcore/fs/proc/Makefile
--- linux/fs/proc/Makefile	Wed Jun 24 22:30:10 1998
+++ linux-2.2.5-elf-kcore/fs/proc/Makefile	Thu Apr  1 10:04:12 1999
@@ -9,7 +9,7 @@
 
 O_TARGET := proc.o
 O_OBJS   := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
-		kmsg.o scsi.o proc_tty.o
+		kmsg.o scsi.o proc_tty.o kcore.o
 ifdef CONFIG_OMIRR
 O_OBJS   := $(O_OBJS) omirr.o
 endif
diff -urN linux/fs/proc/kcore.c linux-2.2.5-elf-kcore/fs/proc/kcore.c
--- linux/fs/proc/kcore.c	Thu Jan  1 01:00:00 1970
+++ linux-2.2.5-elf-kcore/fs/proc/kcore.c	Thu Apr  1 12:53:52 1999
@@ -0,0 +1,281 @@
+/*
+ * kernel ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ * Implemented by David Howells <David.Howells@nexor.co.uk>
+ * Minor modifications by Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/mm.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;
+};
+
+extern char saved_command_line[];
+
+/*****************************************************************************/
+/*
+ * 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() */
+
+/*****************************************************************************/
+/* data structures for registering /proc/kcore_elf */
+
+static struct file_operations elf_kcore_operations = {
+	read:		elf_kcore_read
+};
+
+/* root.c places this into struct proc_dir_entry proc_root_kcore_elf */
+struct inode_operations proc_kcore_elf_inode_operations = {
+	&elf_kcore_operations
+};
diff -urN linux/fs/proc/root.c linux-2.2.5-elf-kcore/fs/proc/root.c
--- linux/fs/proc/root.c	Fri Jan 15 23:38:59 1999
+++ linux-2.2.5-elf-kcore/fs/proc/root.c	Thu Apr  1 10:12:49 1999
@@ -566,6 +566,11 @@
 	S_IFREG | S_IRUSR, 1, 0, 0,
 	0, &proc_kcore_inode_operations
 };
+static struct proc_dir_entry proc_root_kcore_elf = {
+	PROC_KCORE_ELF, 9, "kcore_elf",
+	S_IFREG | S_IRUSR, 1, 0, 0,
+	0, &proc_kcore_elf_inode_operations
+};
 #ifdef CONFIG_MODULES
 static struct proc_dir_entry proc_root_modules = {
 	PROC_MODULES, 7, "modules",
@@ -693,6 +698,8 @@
 #endif
 	proc_register(&proc_root, &proc_root_kcore);
 	proc_root_kcore.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
+	proc_register(&proc_root, &proc_root_kcore_elf);
+	proc_root_kcore_elf.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
 
 #ifdef CONFIG_MODULES
 	proc_register(&proc_root, &proc_root_modules);
diff -urN linux/include/linux/proc_fs.h linux-2.2.5-elf-kcore/include/linux/proc_fs.h
--- linux/include/linux/proc_fs.h	Sun Mar 28 19:03:58 1999
+++ linux-2.2.5-elf-kcore/include/linux/proc_fs.h	Thu Apr  1 10:26:17 1999
@@ -52,7 +52,8 @@
 	PROC_STRAM,
 	PROC_SOUND,
 	PROC_MTRR, /* whether enabled or not */
-	PROC_FS
+	PROC_FS,
+	PROC_KCORE_ELF
 };
 
 enum pid_directory_inos {
@@ -411,6 +412,7 @@
 extern struct inode_operations proc_array_inode_operations;
 extern struct inode_operations proc_arraylong_inode_operations;
 extern struct inode_operations proc_kcore_inode_operations;
+extern struct inode_operations proc_kcore_elf_inode_operations;
 extern struct inode_operations proc_profile_inode_operations;
 extern struct inode_operations proc_kmsg_inode_operations;
 extern struct inode_operations proc_link_inode_operations;



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]