Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Feb 2008 23:17:53 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 135755 for review
Message-ID:  <200802192317.m1JNHrq6036633@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=135755

Change 135755 by jb@jb_freebsd1 on 2008/02/19 23:17:42

	CTF data can be (and usually is) compressed, so we need to do that
	at the time when the data is read from the file.
	
	The ctfoff, typoff and typlen variables in the elf_file struucture
	must be set from outside (by the fbt kernel module) due to
	licensing restrictions. The CTF parsing code is covered by the
	CDDL and the format isn't documented outside the code.
	
	I think I'll propose a clean-room CTF implementation as a
	Google Summer of Code project. It would be nice to be able to
	use the info in DDB.

Affected files ...

.. //depot/projects/dtrace/src/sys/kern/kern_ctf.c#2 edit

Differences ...

==== //depot/projects/dtrace/src/sys/kern/kern_ctf.c#2 (text+ko) ====

@@ -26,15 +26,41 @@
 
 /*
  * Note this file is included by both link_elf.c and link_elf_obj.c.
+ *
+ * The CTF header structure definition can't be used here because it's
+ * (annoyingly) covered by the CDDL. We will just use a few bytes from
+ * it as an integer array where we 'know' what they mean.
  */
+#define CTF_HDR_SIZE		36
+#define CTF_HDR_STRTAB_U32	7
+#define CTF_HDR_STRLEN_U32	8
+
+#ifdef DDB_CTF
+static void *
+z_alloc(void *nil, u_int items, u_int size)
+{
+	void *ptr;
+
+	ptr = malloc(items * size, M_TEMP, M_NOWAIT);
+	return ptr;
+}
 
+static void
+z_free(void *nil, void *ptr)
+{
+	free(ptr, M_TEMP);
+}
+
+#endif
+
 static int
-link_elf_ctf_get(linker_file_t lf, const uint8_t **data, int *len)
+link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc)
 {
 #ifdef DDB_CTF
 	Elf_Ehdr *hdr = NULL;
 	Elf_Shdr *shdr = NULL;
 	caddr_t ctftab = NULL;
+	caddr_t raw = NULL;
 	caddr_t shstrtab = NULL;
 	elf_file_t ef = (elf_file_t) lf;
 	int flags;
@@ -42,18 +68,18 @@
 	int nbytes;
 	int resid;
 	int vfslocked;
+	size_t sz;
 	struct nameidata nd;
 	struct thread *td = curthread;
-	
+	uint8_t ctf_hdr[CTF_HDR_SIZE];
 #endif
 	int error = 0;
 
-	if (lf == NULL || data == NULL || len == NULL)
+	if (lf == NULL || lc == NULL)
 		return (EINVAL);
 
 	/* Set the defaults for no CTF present. That's not a crime! */
-	*data = NULL;
-	*len = 0;
+	bzero(lc, sizeof(*lc));
 
 #ifdef DDB_CTF
 	/*
@@ -67,8 +93,15 @@
 	/* Now check if we've already loaded the CTF data.. */
 	if (ef->ctfcnt > 0) {
 		/* We only need to load once. */
-		*data = ef->ctftab;
-		*len = ef->ctfcnt;
+		lc->ctftab = ef->ctftab;
+		lc->ctfcnt = ef->ctfcnt;
+		lc->symtab = ef->ddbsymtab;
+		lc->strtab = ef->ddbstrtab;
+		lc->strcnt = ef->ddbstrcnt;
+		lc->nsym   = ef->ddbsymcnt;
+		lc->ctfoffp = (uint32_t **) &ef->ctfoff;
+		lc->typoffp = (uint32_t **) &ef->typoff;
+		lc->typlenp = &ef->typlen;
 		return (0);
 	}
 
@@ -155,18 +188,100 @@
 	if (i >= hdr->e_shnum)
 		goto out;
 
-	/* Allocate memory to buffer the CTF data. */
-	if ((ctftab = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK)) == NULL) {
+	/* Read the CTF header. */
+	if ((error = vn_rdwr(UIO_READ, nd.ni_vp, ctf_hdr, sizeof(ctf_hdr),
+	    shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
+	    NOCRED, &resid, td)) != 0)
+		goto out;
+
+	/* Check the CTF magic number. (XXX check for big endian!) */
+	if (ctf_hdr[0] != 0xf1 || ctf_hdr[1] != 0xcf)
+		goto out;
+
+	/* Check if version 2. */
+	if (ctf_hdr[2] != 2)
+		goto out;
+
+	/* Check if the data is compressed. */
+	if ((ctf_hdr[3] & 0x1) != 0) {
+		uint32_t *u32 = (uint32_t *) ctf_hdr;
+
+		/*
+		 * The last two fields in the CTF header are the offset
+		 * from the end of the header to the start of the string
+		 * data and the length of that string data. se this
+		 * information to determine the decompressed CTF data
+		 * buffer required.
+		 */
+		sz = u32[CTF_HDR_STRTAB_U32] + u32[CTF_HDR_STRLEN_U32] +
+		    sizeof(ctf_hdr);
+
+		/*
+		 * Allocate memory for the compressed CTF data, including
+		 * the header (which isn't compressed).
+		 */
+		if ((raw = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK)) == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+	} else {
+		/*
+		 * The CTF data is not compressed, so the ELF section
+		 * size is the same as the buffer size required.
+		 */
+		sz = shdr[i].sh_size;
+	}
+
+	/*
+	 * Allocate memory to buffer the CTF data in it's decompressed
+	 * form.
+	 */
+	if ((ctftab = malloc(sz, M_LINKER, M_WAITOK)) == NULL) {
 		error = ENOMEM;
 		goto out;
 	}
 
-	/* Read the CTF data. */
-	if ((error = vn_rdwr(UIO_READ, nd.ni_vp, ctftab, shdr[i].sh_size,
-	    shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
-	    NOCRED, &resid, td)) != 0)
+	/*
+	 * Read the CTF data into the raw buffer if compressed, or
+	 * directly into the CTF buffer otherwise.
+	 */
+	if ((error = vn_rdwr(UIO_READ, nd.ni_vp, raw == NULL ? ctftab : raw,
+	    shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED,
+	    td->td_ucred, NOCRED, &resid, td)) != 0)
 		goto out;
 
+	/* Check if decompression is required. */
+	if (raw != NULL) {
+		z_stream zs;
+		int ret;
+
+		/*
+		 * The header isn't compressed, so copy that into the
+		 * CTF buffer first.
+		 */
+		bcopy(ctf_hdr, ctftab, sizeof(ctf_hdr));
+
+		/* Initialise the zlib structure. */
+		bzero(&zs, sizeof(zs));
+		zs.zalloc = z_alloc;
+		zs.zfree = z_free;
+
+		if (inflateInit(&zs) != Z_OK) {
+			error = EIO;
+			goto out;
+		}
+
+		zs.avail_in = shdr[i].sh_size - sizeof(ctf_hdr);
+		zs.next_in = ((uint8_t *) raw) + sizeof(ctf_hdr);
+		zs.avail_out = sz - sizeof(ctf_hdr);
+		zs.next_out = ((uint8_t *) ctftab) + sizeof(ctf_hdr);
+		if ((ret = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
+			printf("%s(%d): zlib inflate returned %d\n", __func__, __LINE__, ret);
+			error = EIO;
+			goto out;
+		}
+	}
+
 	/* Got the CTF data! */
 	ef->ctftab = ctftab;
 	ef->ctfcnt = shdr[i].sh_size;
@@ -175,8 +290,15 @@
 	ctftab = NULL;
 
 	/* Let the caller use the CTF data read. */
-	*data = ef->ctftab;
-	*len = ef->ctfcnt;
+	lc->ctftab = ef->ctftab;
+	lc->ctfcnt = ef->ctfcnt;
+	lc->symtab = ef->ddbsymtab;
+	lc->strtab = ef->ddbstrtab;
+	lc->strcnt = ef->ddbstrcnt;
+	lc->nsym   = ef->ddbsymcnt;
+	lc->ctfoffp = (uint32_t **) &ef->ctfoff;
+	lc->typoffp = (uint32_t **) &ef->typoff;
+	lc->typlenp = &ef->typlen;
 
 out:
 	VOP_UNLOCK(nd.ni_vp, 0);
@@ -191,6 +313,8 @@
 		free(shstrtab, M_LINKER);
 	if (ctftab != NULL)
 		free(ctftab, M_LINKER);
+	if (raw != NULL)
+		free(raw, M_LINKER);
 #else
 	error = EOPNOTSUPP;
 #endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802192317.m1JNHrq6036633>