From owner-p4-projects@FreeBSD.ORG Tue Feb 19 23:17:54 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 76C1E16A41B; Tue, 19 Feb 2008 23:17:54 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3B6D416A419 for ; Tue, 19 Feb 2008 23:17:54 +0000 (UTC) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 1A31013C461 for ; Tue, 19 Feb 2008 23:17:54 +0000 (UTC) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m1JNHr1m036636 for ; Tue, 19 Feb 2008 23:17:53 GMT (envelope-from jb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m1JNHrq6036633 for perforce@freebsd.org; Tue, 19 Feb 2008 23:17:53 GMT (envelope-from jb@freebsd.org) Date: Tue, 19 Feb 2008 23:17:53 GMT Message-Id: <200802192317.m1JNHrq6036633@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jb@freebsd.org using -f From: John Birrell To: Perforce Change Reviews Cc: Subject: PERFORCE change 135755 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Feb 2008 23:17:54 -0000 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