175d94ef6SJohn Birrell /*- 275d94ef6SJohn Birrell * Copyright (c) 2008 John Birrell <jb@freebsd.org> 375d94ef6SJohn Birrell * All rights reserved. 475d94ef6SJohn Birrell * 575d94ef6SJohn Birrell * Redistribution and use in source and binary forms, with or without 675d94ef6SJohn Birrell * modification, are permitted provided that the following conditions 775d94ef6SJohn Birrell * are met: 875d94ef6SJohn Birrell * 1. Redistributions of source code must retain the above copyright 975d94ef6SJohn Birrell * notice, this list of conditions and the following disclaimer. 1075d94ef6SJohn Birrell * 2. Redistributions in binary form must reproduce the above copyright 1175d94ef6SJohn Birrell * notice, this list of conditions and the following disclaimer in the 1275d94ef6SJohn Birrell * documentation and/or other materials provided with the distribution. 1375d94ef6SJohn Birrell * 1475d94ef6SJohn Birrell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575d94ef6SJohn Birrell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675d94ef6SJohn Birrell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775d94ef6SJohn Birrell * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875d94ef6SJohn Birrell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975d94ef6SJohn Birrell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075d94ef6SJohn Birrell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175d94ef6SJohn Birrell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275d94ef6SJohn Birrell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375d94ef6SJohn Birrell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475d94ef6SJohn Birrell * SUCH DAMAGE. 2575d94ef6SJohn Birrell * 2675d94ef6SJohn Birrell * $FreeBSD$ 2775d94ef6SJohn Birrell */ 2875d94ef6SJohn Birrell 2975d94ef6SJohn Birrell /* 3075d94ef6SJohn Birrell * Note this file is included by both link_elf.c and link_elf_obj.c. 3175d94ef6SJohn Birrell * 3275d94ef6SJohn Birrell * The CTF header structure definition can't be used here because it's 3375d94ef6SJohn Birrell * (annoyingly) covered by the CDDL. We will just use a few bytes from 3475d94ef6SJohn Birrell * it as an integer array where we 'know' what they mean. 3575d94ef6SJohn Birrell */ 3675d94ef6SJohn Birrell #define CTF_HDR_SIZE 36 3775d94ef6SJohn Birrell #define CTF_HDR_STRTAB_U32 7 3875d94ef6SJohn Birrell #define CTF_HDR_STRLEN_U32 8 3975d94ef6SJohn Birrell 4075d94ef6SJohn Birrell #ifdef DDB_CTF 4175d94ef6SJohn Birrell static void * 4275d94ef6SJohn Birrell z_alloc(void *nil, u_int items, u_int size) 4375d94ef6SJohn Birrell { 4475d94ef6SJohn Birrell void *ptr; 4575d94ef6SJohn Birrell 4675d94ef6SJohn Birrell ptr = malloc(items * size, M_TEMP, M_NOWAIT); 4775d94ef6SJohn Birrell return ptr; 4875d94ef6SJohn Birrell } 4975d94ef6SJohn Birrell 5075d94ef6SJohn Birrell static void 5175d94ef6SJohn Birrell z_free(void *nil, void *ptr) 5275d94ef6SJohn Birrell { 5375d94ef6SJohn Birrell free(ptr, M_TEMP); 5475d94ef6SJohn Birrell } 5575d94ef6SJohn Birrell 5675d94ef6SJohn Birrell #endif 5775d94ef6SJohn Birrell 5875d94ef6SJohn Birrell static int 5975d94ef6SJohn Birrell link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc) 6075d94ef6SJohn Birrell { 6175d94ef6SJohn Birrell #ifdef DDB_CTF 6275d94ef6SJohn Birrell Elf_Ehdr *hdr = NULL; 6375d94ef6SJohn Birrell Elf_Shdr *shdr = NULL; 6475d94ef6SJohn Birrell caddr_t ctftab = NULL; 6575d94ef6SJohn Birrell caddr_t raw = NULL; 6675d94ef6SJohn Birrell caddr_t shstrtab = NULL; 6775d94ef6SJohn Birrell elf_file_t ef = (elf_file_t) lf; 6875d94ef6SJohn Birrell int flags; 6975d94ef6SJohn Birrell int i; 7075d94ef6SJohn Birrell int nbytes; 7175d94ef6SJohn Birrell int resid; 7275d94ef6SJohn Birrell int vfslocked; 7375d94ef6SJohn Birrell size_t sz; 7475d94ef6SJohn Birrell struct nameidata nd; 7575d94ef6SJohn Birrell struct thread *td = curthread; 7675d94ef6SJohn Birrell uint8_t ctf_hdr[CTF_HDR_SIZE]; 7775d94ef6SJohn Birrell #endif 7875d94ef6SJohn Birrell int error = 0; 7975d94ef6SJohn Birrell 8075d94ef6SJohn Birrell if (lf == NULL || lc == NULL) 8175d94ef6SJohn Birrell return (EINVAL); 8275d94ef6SJohn Birrell 8375d94ef6SJohn Birrell /* Set the defaults for no CTF present. That's not a crime! */ 8475d94ef6SJohn Birrell bzero(lc, sizeof(*lc)); 8575d94ef6SJohn Birrell 8675d94ef6SJohn Birrell #ifdef DDB_CTF 8775d94ef6SJohn Birrell /* 8875d94ef6SJohn Birrell * First check if we've tried to load CTF data previously and the 8975d94ef6SJohn Birrell * CTF ELF section wasn't found. We flag that condition by setting 9075d94ef6SJohn Birrell * ctfcnt to -1. See below. 9175d94ef6SJohn Birrell */ 9275d94ef6SJohn Birrell if (ef->ctfcnt < 0) 93*6f6924e5SRyan Stone return (EFTYPE); 9475d94ef6SJohn Birrell 9575d94ef6SJohn Birrell /* Now check if we've already loaded the CTF data.. */ 9675d94ef6SJohn Birrell if (ef->ctfcnt > 0) { 9775d94ef6SJohn Birrell /* We only need to load once. */ 9875d94ef6SJohn Birrell lc->ctftab = ef->ctftab; 9975d94ef6SJohn Birrell lc->ctfcnt = ef->ctfcnt; 10075d94ef6SJohn Birrell lc->symtab = ef->ddbsymtab; 10175d94ef6SJohn Birrell lc->strtab = ef->ddbstrtab; 10275d94ef6SJohn Birrell lc->strcnt = ef->ddbstrcnt; 10375d94ef6SJohn Birrell lc->nsym = ef->ddbsymcnt; 10475d94ef6SJohn Birrell lc->ctfoffp = (uint32_t **) &ef->ctfoff; 10575d94ef6SJohn Birrell lc->typoffp = (uint32_t **) &ef->typoff; 10675d94ef6SJohn Birrell lc->typlenp = &ef->typlen; 10775d94ef6SJohn Birrell return (0); 10875d94ef6SJohn Birrell } 10975d94ef6SJohn Birrell 11075d94ef6SJohn Birrell /* 11175d94ef6SJohn Birrell * We need to try reading the CTF data. Flag no CTF data present 11275d94ef6SJohn Birrell * by default and if we actually succeed in reading it, we'll 11375d94ef6SJohn Birrell * update ctfcnt to the number of bytes read. 11475d94ef6SJohn Birrell */ 11575d94ef6SJohn Birrell ef->ctfcnt = -1; 11675d94ef6SJohn Birrell 11775d94ef6SJohn Birrell NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, lf->pathname, td); 11875d94ef6SJohn Birrell flags = FREAD; 11975d94ef6SJohn Birrell error = vn_open(&nd, &flags, 0, NULL); 12075d94ef6SJohn Birrell if (error) 12175d94ef6SJohn Birrell return (error); 12275d94ef6SJohn Birrell vfslocked = NDHASGIANT(&nd); 12375d94ef6SJohn Birrell NDFREE(&nd, NDF_ONLY_PNBUF); 12475d94ef6SJohn Birrell 12575d94ef6SJohn Birrell /* Allocate memory for the FLF header. */ 12675d94ef6SJohn Birrell if ((hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK)) == NULL) { 12775d94ef6SJohn Birrell error = ENOMEM; 12875d94ef6SJohn Birrell goto out; 12975d94ef6SJohn Birrell } 13075d94ef6SJohn Birrell 13175d94ef6SJohn Birrell /* Read the ELF header. */ 13275d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, hdr, sizeof(*hdr), 13375d94ef6SJohn Birrell 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, 13475d94ef6SJohn Birrell td)) != 0) 13575d94ef6SJohn Birrell goto out; 13675d94ef6SJohn Birrell 13775d94ef6SJohn Birrell /* Sanity check. */ 13875d94ef6SJohn Birrell if (!IS_ELF(*hdr)) { 13975d94ef6SJohn Birrell error = ENOEXEC; 14075d94ef6SJohn Birrell goto out; 14175d94ef6SJohn Birrell } 14275d94ef6SJohn Birrell 14375d94ef6SJohn Birrell nbytes = hdr->e_shnum * hdr->e_shentsize; 14475d94ef6SJohn Birrell if (nbytes == 0 || hdr->e_shoff == 0 || 14575d94ef6SJohn Birrell hdr->e_shentsize != sizeof(Elf_Shdr)) { 14675d94ef6SJohn Birrell error = ENOEXEC; 14775d94ef6SJohn Birrell goto out; 14875d94ef6SJohn Birrell } 14975d94ef6SJohn Birrell 15075d94ef6SJohn Birrell /* Allocate memory for all the section headers */ 15175d94ef6SJohn Birrell if ((shdr = malloc(nbytes, M_LINKER, M_WAITOK)) == NULL) { 15275d94ef6SJohn Birrell error = ENOMEM; 15375d94ef6SJohn Birrell goto out; 15475d94ef6SJohn Birrell } 15575d94ef6SJohn Birrell 15675d94ef6SJohn Birrell /* Read all the section headers */ 15775d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)shdr, nbytes, 15875d94ef6SJohn Birrell hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 15975d94ef6SJohn Birrell &resid, td)) != 0) 16075d94ef6SJohn Birrell goto out; 16175d94ef6SJohn Birrell 16275d94ef6SJohn Birrell /* 16375d94ef6SJohn Birrell * We need to search for the CTF section by name, so if the 16475d94ef6SJohn Birrell * section names aren't present, then we can't locate the 16575d94ef6SJohn Birrell * .SUNW_ctf section containing the CTF data. 16675d94ef6SJohn Birrell */ 1672b03effaSXin LI if (hdr->e_shstrndx == 0 || shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { 1682b03effaSXin LI printf("%s(%d): module %s e_shstrndx is %d, sh_type is %d\n", 1692b03effaSXin LI __func__, __LINE__, lf->pathname, hdr->e_shstrndx, 1702b03effaSXin LI shdr[hdr->e_shstrndx].sh_type); 1712b03effaSXin LI error = EFTYPE; 17275d94ef6SJohn Birrell goto out; 1732b03effaSXin LI } 17475d94ef6SJohn Birrell 17575d94ef6SJohn Birrell /* Allocate memory to buffer the section header strings. */ 17675d94ef6SJohn Birrell if ((shstrtab = malloc(shdr[hdr->e_shstrndx].sh_size, M_LINKER, 17775d94ef6SJohn Birrell M_WAITOK)) == NULL) { 17875d94ef6SJohn Birrell error = ENOMEM; 17975d94ef6SJohn Birrell goto out; 18075d94ef6SJohn Birrell } 18175d94ef6SJohn Birrell 18275d94ef6SJohn Birrell /* Read the section header strings. */ 18375d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, shstrtab, 18475d94ef6SJohn Birrell shdr[hdr->e_shstrndx].sh_size, shdr[hdr->e_shstrndx].sh_offset, 18575d94ef6SJohn Birrell UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, 18675d94ef6SJohn Birrell td)) != 0) 18775d94ef6SJohn Birrell goto out; 18875d94ef6SJohn Birrell 18975d94ef6SJohn Birrell /* Search for the section containing the CTF data. */ 19075d94ef6SJohn Birrell for (i = 0; i < hdr->e_shnum; i++) 19175d94ef6SJohn Birrell if (strcmp(".SUNW_ctf", shstrtab + shdr[i].sh_name) == 0) 19275d94ef6SJohn Birrell break; 19375d94ef6SJohn Birrell 19475d94ef6SJohn Birrell /* Check if the CTF section wasn't found. */ 1952b03effaSXin LI if (i >= hdr->e_shnum) { 1962b03effaSXin LI printf("%s(%d): module %s has no .SUNW_ctf section\n", 1972b03effaSXin LI __func__, __LINE__, lf->pathname); 1982b03effaSXin LI error = EFTYPE; 19975d94ef6SJohn Birrell goto out; 2002b03effaSXin LI } 20175d94ef6SJohn Birrell 20275d94ef6SJohn Birrell /* Read the CTF header. */ 20375d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, ctf_hdr, sizeof(ctf_hdr), 20475d94ef6SJohn Birrell shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, 20575d94ef6SJohn Birrell NOCRED, &resid, td)) != 0) 20675d94ef6SJohn Birrell goto out; 20775d94ef6SJohn Birrell 20875d94ef6SJohn Birrell /* Check the CTF magic number. (XXX check for big endian!) */ 2092b03effaSXin LI if (ctf_hdr[0] != 0xf1 || ctf_hdr[1] != 0xcf) { 2102b03effaSXin LI printf("%s(%d): module %s has invalid format\n", 2112b03effaSXin LI __func__, __LINE__, lf->pathname); 2122b03effaSXin LI error = EFTYPE; 21375d94ef6SJohn Birrell goto out; 2142b03effaSXin LI } 21575d94ef6SJohn Birrell 21675d94ef6SJohn Birrell /* Check if version 2. */ 2172b03effaSXin LI if (ctf_hdr[2] != 2) { 2182b03effaSXin LI printf("%s(%d): module %s CTF format version is %d " 2192b03effaSXin LI "(2 expected)\n", 2202b03effaSXin LI __func__, __LINE__, lf->pathname, ctf_hdr[2]); 2212b03effaSXin LI error = EFTYPE; 22275d94ef6SJohn Birrell goto out; 2232b03effaSXin LI } 22475d94ef6SJohn Birrell 22575d94ef6SJohn Birrell /* Check if the data is compressed. */ 22675d94ef6SJohn Birrell if ((ctf_hdr[3] & 0x1) != 0) { 22775d94ef6SJohn Birrell uint32_t *u32 = (uint32_t *) ctf_hdr; 22875d94ef6SJohn Birrell 22975d94ef6SJohn Birrell /* 23075d94ef6SJohn Birrell * The last two fields in the CTF header are the offset 23175d94ef6SJohn Birrell * from the end of the header to the start of the string 23275d94ef6SJohn Birrell * data and the length of that string data. se this 23375d94ef6SJohn Birrell * information to determine the decompressed CTF data 23475d94ef6SJohn Birrell * buffer required. 23575d94ef6SJohn Birrell */ 23675d94ef6SJohn Birrell sz = u32[CTF_HDR_STRTAB_U32] + u32[CTF_HDR_STRLEN_U32] + 23775d94ef6SJohn Birrell sizeof(ctf_hdr); 23875d94ef6SJohn Birrell 23975d94ef6SJohn Birrell /* 24075d94ef6SJohn Birrell * Allocate memory for the compressed CTF data, including 24175d94ef6SJohn Birrell * the header (which isn't compressed). 24275d94ef6SJohn Birrell */ 24375d94ef6SJohn Birrell if ((raw = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK)) == NULL) { 24475d94ef6SJohn Birrell error = ENOMEM; 24575d94ef6SJohn Birrell goto out; 24675d94ef6SJohn Birrell } 24775d94ef6SJohn Birrell } else { 24875d94ef6SJohn Birrell /* 24975d94ef6SJohn Birrell * The CTF data is not compressed, so the ELF section 25075d94ef6SJohn Birrell * size is the same as the buffer size required. 25175d94ef6SJohn Birrell */ 25275d94ef6SJohn Birrell sz = shdr[i].sh_size; 25375d94ef6SJohn Birrell } 25475d94ef6SJohn Birrell 25575d94ef6SJohn Birrell /* 25675d94ef6SJohn Birrell * Allocate memory to buffer the CTF data in it's decompressed 25775d94ef6SJohn Birrell * form. 25875d94ef6SJohn Birrell */ 25975d94ef6SJohn Birrell if ((ctftab = malloc(sz, M_LINKER, M_WAITOK)) == NULL) { 26075d94ef6SJohn Birrell error = ENOMEM; 26175d94ef6SJohn Birrell goto out; 26275d94ef6SJohn Birrell } 26375d94ef6SJohn Birrell 26475d94ef6SJohn Birrell /* 26575d94ef6SJohn Birrell * Read the CTF data into the raw buffer if compressed, or 26675d94ef6SJohn Birrell * directly into the CTF buffer otherwise. 26775d94ef6SJohn Birrell */ 26875d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, raw == NULL ? ctftab : raw, 26975d94ef6SJohn Birrell shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, 27075d94ef6SJohn Birrell td->td_ucred, NOCRED, &resid, td)) != 0) 27175d94ef6SJohn Birrell goto out; 27275d94ef6SJohn Birrell 27375d94ef6SJohn Birrell /* Check if decompression is required. */ 27475d94ef6SJohn Birrell if (raw != NULL) { 27575d94ef6SJohn Birrell z_stream zs; 27675d94ef6SJohn Birrell int ret; 27775d94ef6SJohn Birrell 27875d94ef6SJohn Birrell /* 27975d94ef6SJohn Birrell * The header isn't compressed, so copy that into the 28075d94ef6SJohn Birrell * CTF buffer first. 28175d94ef6SJohn Birrell */ 28275d94ef6SJohn Birrell bcopy(ctf_hdr, ctftab, sizeof(ctf_hdr)); 28375d94ef6SJohn Birrell 28475d94ef6SJohn Birrell /* Initialise the zlib structure. */ 28575d94ef6SJohn Birrell bzero(&zs, sizeof(zs)); 28675d94ef6SJohn Birrell zs.zalloc = z_alloc; 28775d94ef6SJohn Birrell zs.zfree = z_free; 28875d94ef6SJohn Birrell 28975d94ef6SJohn Birrell if (inflateInit(&zs) != Z_OK) { 29075d94ef6SJohn Birrell error = EIO; 29175d94ef6SJohn Birrell goto out; 29275d94ef6SJohn Birrell } 29375d94ef6SJohn Birrell 29475d94ef6SJohn Birrell zs.avail_in = shdr[i].sh_size - sizeof(ctf_hdr); 29575d94ef6SJohn Birrell zs.next_in = ((uint8_t *) raw) + sizeof(ctf_hdr); 29675d94ef6SJohn Birrell zs.avail_out = sz - sizeof(ctf_hdr); 29775d94ef6SJohn Birrell zs.next_out = ((uint8_t *) ctftab) + sizeof(ctf_hdr); 29875d94ef6SJohn Birrell if ((ret = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { 29975d94ef6SJohn Birrell printf("%s(%d): zlib inflate returned %d\n", __func__, __LINE__, ret); 30075d94ef6SJohn Birrell error = EIO; 30175d94ef6SJohn Birrell goto out; 30275d94ef6SJohn Birrell } 30375d94ef6SJohn Birrell } 30475d94ef6SJohn Birrell 30575d94ef6SJohn Birrell /* Got the CTF data! */ 30675d94ef6SJohn Birrell ef->ctftab = ctftab; 30775d94ef6SJohn Birrell ef->ctfcnt = shdr[i].sh_size; 30875d94ef6SJohn Birrell 30975d94ef6SJohn Birrell /* We'll retain the memory allocated for the CTF data. */ 31075d94ef6SJohn Birrell ctftab = NULL; 31175d94ef6SJohn Birrell 31275d94ef6SJohn Birrell /* Let the caller use the CTF data read. */ 31375d94ef6SJohn Birrell lc->ctftab = ef->ctftab; 31475d94ef6SJohn Birrell lc->ctfcnt = ef->ctfcnt; 31575d94ef6SJohn Birrell lc->symtab = ef->ddbsymtab; 31675d94ef6SJohn Birrell lc->strtab = ef->ddbstrtab; 31775d94ef6SJohn Birrell lc->strcnt = ef->ddbstrcnt; 31875d94ef6SJohn Birrell lc->nsym = ef->ddbsymcnt; 31975d94ef6SJohn Birrell lc->ctfoffp = (uint32_t **) &ef->ctfoff; 32075d94ef6SJohn Birrell lc->typoffp = (uint32_t **) &ef->typoff; 32175d94ef6SJohn Birrell lc->typlenp = &ef->typlen; 32275d94ef6SJohn Birrell 32375d94ef6SJohn Birrell out: 32475d94ef6SJohn Birrell VOP_UNLOCK(nd.ni_vp, 0); 32575d94ef6SJohn Birrell vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 32675d94ef6SJohn Birrell VFS_UNLOCK_GIANT(vfslocked); 32775d94ef6SJohn Birrell 32875d94ef6SJohn Birrell if (hdr != NULL) 32975d94ef6SJohn Birrell free(hdr, M_LINKER); 33075d94ef6SJohn Birrell if (shdr != NULL) 33175d94ef6SJohn Birrell free(shdr, M_LINKER); 33275d94ef6SJohn Birrell if (shstrtab != NULL) 33375d94ef6SJohn Birrell free(shstrtab, M_LINKER); 33475d94ef6SJohn Birrell if (ctftab != NULL) 33575d94ef6SJohn Birrell free(ctftab, M_LINKER); 33675d94ef6SJohn Birrell if (raw != NULL) 33775d94ef6SJohn Birrell free(raw, M_LINKER); 33875d94ef6SJohn Birrell #else 33975d94ef6SJohn Birrell error = EOPNOTSUPP; 34075d94ef6SJohn Birrell #endif 34175d94ef6SJohn Birrell 34275d94ef6SJohn Birrell return (error); 34375d94ef6SJohn Birrell } 344