175d94ef6SJohn Birrell /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 475d94ef6SJohn Birrell * Copyright (c) 2008 John Birrell <jb@freebsd.org> 575d94ef6SJohn Birrell * All rights reserved. 675d94ef6SJohn Birrell * 775d94ef6SJohn Birrell * Redistribution and use in source and binary forms, with or without 875d94ef6SJohn Birrell * modification, are permitted provided that the following conditions 975d94ef6SJohn Birrell * are met: 1075d94ef6SJohn Birrell * 1. Redistributions of source code must retain the above copyright 1175d94ef6SJohn Birrell * notice, this list of conditions and the following disclaimer. 1275d94ef6SJohn Birrell * 2. Redistributions in binary form must reproduce the above copyright 1375d94ef6SJohn Birrell * notice, this list of conditions and the following disclaimer in the 1475d94ef6SJohn Birrell * documentation and/or other materials provided with the distribution. 1575d94ef6SJohn Birrell * 1675d94ef6SJohn Birrell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1775d94ef6SJohn Birrell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1875d94ef6SJohn Birrell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1975d94ef6SJohn Birrell * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2075d94ef6SJohn Birrell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2175d94ef6SJohn Birrell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2275d94ef6SJohn Birrell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2375d94ef6SJohn Birrell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2475d94ef6SJohn Birrell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2575d94ef6SJohn Birrell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2675d94ef6SJohn Birrell * SUCH DAMAGE. 2775d94ef6SJohn Birrell */ 2875d94ef6SJohn Birrell 29cab9382aSMark Johnston #include <sys/ctf.h> 30c21bc6f3SBojan Novković #include <sys/kdb.h> 31c21bc6f3SBojan Novković #include <sys/linker.h> 32c21bc6f3SBojan Novković 33c21bc6f3SBojan Novković #include <ddb/db_ctf.h> 34cab9382aSMark Johnston 3575d94ef6SJohn Birrell /* 3675d94ef6SJohn Birrell * Note this file is included by both link_elf.c and link_elf_obj.c. 3775d94ef6SJohn Birrell */ 3875d94ef6SJohn Birrell 3975d94ef6SJohn Birrell #ifdef DDB_CTF 4022bbc4b2SXin LI #include <contrib/zlib/zlib.h> 4175d94ef6SJohn Birrell #endif 4275d94ef6SJohn Birrell 4375d94ef6SJohn Birrell static int 4475d94ef6SJohn Birrell link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc) 4575d94ef6SJohn Birrell { 4675d94ef6SJohn Birrell #ifdef DDB_CTF 4775d94ef6SJohn Birrell Elf_Ehdr *hdr = NULL; 4875d94ef6SJohn Birrell Elf_Shdr *shdr = NULL; 4975d94ef6SJohn Birrell caddr_t ctftab = NULL; 5075d94ef6SJohn Birrell caddr_t raw = NULL; 5175d94ef6SJohn Birrell caddr_t shstrtab = NULL; 5275d94ef6SJohn Birrell elf_file_t ef = (elf_file_t) lf; 5375d94ef6SJohn Birrell int flags; 5475d94ef6SJohn Birrell int i; 5575d94ef6SJohn Birrell int nbytes; 5675d94ef6SJohn Birrell size_t sz; 5775d94ef6SJohn Birrell struct nameidata nd; 5875d94ef6SJohn Birrell struct thread *td = curthread; 59cab9382aSMark Johnston struct ctf_header cth; 6075d94ef6SJohn Birrell #endif 6175d94ef6SJohn Birrell int error = 0; 6275d94ef6SJohn Birrell 6375d94ef6SJohn Birrell if (lf == NULL || lc == NULL) 6475d94ef6SJohn Birrell return (EINVAL); 6575d94ef6SJohn Birrell 6675d94ef6SJohn Birrell /* Set the defaults for no CTF present. That's not a crime! */ 6775d94ef6SJohn Birrell bzero(lc, sizeof(*lc)); 6875d94ef6SJohn Birrell 6975d94ef6SJohn Birrell #ifdef DDB_CTF 7075d94ef6SJohn Birrell /* 7175d94ef6SJohn Birrell * First check if we've tried to load CTF data previously and the 7275d94ef6SJohn Birrell * CTF ELF section wasn't found. We flag that condition by setting 7375d94ef6SJohn Birrell * ctfcnt to -1. See below. 7475d94ef6SJohn Birrell */ 7575d94ef6SJohn Birrell if (ef->ctfcnt < 0) 766f6924e5SRyan Stone return (EFTYPE); 7775d94ef6SJohn Birrell 7875d94ef6SJohn Birrell /* Now check if we've already loaded the CTF data.. */ 7975d94ef6SJohn Birrell if (ef->ctfcnt > 0) { 8075d94ef6SJohn Birrell /* We only need to load once. */ 8175d94ef6SJohn Birrell lc->ctftab = ef->ctftab; 8275d94ef6SJohn Birrell lc->ctfcnt = ef->ctfcnt; 8375d94ef6SJohn Birrell lc->symtab = ef->ddbsymtab; 8475d94ef6SJohn Birrell lc->strtab = ef->ddbstrtab; 8575d94ef6SJohn Birrell lc->strcnt = ef->ddbstrcnt; 8675d94ef6SJohn Birrell lc->nsym = ef->ddbsymcnt; 8775d94ef6SJohn Birrell lc->ctfoffp = (uint32_t **) &ef->ctfoff; 8875d94ef6SJohn Birrell lc->typoffp = (uint32_t **) &ef->typoff; 8975d94ef6SJohn Birrell lc->typlenp = &ef->typlen; 9075d94ef6SJohn Birrell return (0); 9175d94ef6SJohn Birrell } 9275d94ef6SJohn Birrell 93c21bc6f3SBojan Novković if (panicstr != NULL || kdb_active) 94c21bc6f3SBojan Novković return (ENXIO); 95c21bc6f3SBojan Novković 9675d94ef6SJohn Birrell /* 9775d94ef6SJohn Birrell * We need to try reading the CTF data. Flag no CTF data present 9875d94ef6SJohn Birrell * by default and if we actually succeed in reading it, we'll 9975d94ef6SJohn Birrell * update ctfcnt to the number of bytes read. 10075d94ef6SJohn Birrell */ 10175d94ef6SJohn Birrell ef->ctfcnt = -1; 10275d94ef6SJohn Birrell 1037e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, lf->pathname); 10475d94ef6SJohn Birrell flags = FREAD; 10575d94ef6SJohn Birrell error = vn_open(&nd, &flags, 0, NULL); 10675d94ef6SJohn Birrell if (error) 10775d94ef6SJohn Birrell return (error); 108bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 10975d94ef6SJohn Birrell 11075d94ef6SJohn Birrell /* Allocate memory for the FLF header. */ 111ce47682cSMark Johnston hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK); 11275d94ef6SJohn Birrell 11375d94ef6SJohn Birrell /* Read the ELF header. */ 11475d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, hdr, sizeof(*hdr), 1157abb0b09SMark Johnston 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, NULL, 11675d94ef6SJohn Birrell td)) != 0) 11775d94ef6SJohn Birrell goto out; 11875d94ef6SJohn Birrell 11975d94ef6SJohn Birrell /* Sanity check. */ 12075d94ef6SJohn Birrell if (!IS_ELF(*hdr)) { 12175d94ef6SJohn Birrell error = ENOEXEC; 12275d94ef6SJohn Birrell goto out; 12375d94ef6SJohn Birrell } 12475d94ef6SJohn Birrell 12575d94ef6SJohn Birrell nbytes = hdr->e_shnum * hdr->e_shentsize; 12675d94ef6SJohn Birrell if (nbytes == 0 || hdr->e_shoff == 0 || 12775d94ef6SJohn Birrell hdr->e_shentsize != sizeof(Elf_Shdr)) { 12875d94ef6SJohn Birrell error = ENOEXEC; 12975d94ef6SJohn Birrell goto out; 13075d94ef6SJohn Birrell } 13175d94ef6SJohn Birrell 13275d94ef6SJohn Birrell /* Allocate memory for all the section headers */ 133ce47682cSMark Johnston shdr = malloc(nbytes, M_LINKER, M_WAITOK); 13475d94ef6SJohn Birrell 13575d94ef6SJohn Birrell /* Read all the section headers */ 13675d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)shdr, nbytes, 13775d94ef6SJohn Birrell hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 1387abb0b09SMark Johnston NULL, td)) != 0) 13975d94ef6SJohn Birrell goto out; 14075d94ef6SJohn Birrell 14175d94ef6SJohn Birrell /* 14275d94ef6SJohn Birrell * We need to search for the CTF section by name, so if the 14375d94ef6SJohn Birrell * section names aren't present, then we can't locate the 14475d94ef6SJohn Birrell * .SUNW_ctf section containing the CTF data. 14575d94ef6SJohn Birrell */ 1462b03effaSXin LI if (hdr->e_shstrndx == 0 || shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { 1472b03effaSXin LI printf("%s(%d): module %s e_shstrndx is %d, sh_type is %d\n", 1482b03effaSXin LI __func__, __LINE__, lf->pathname, hdr->e_shstrndx, 1492b03effaSXin LI shdr[hdr->e_shstrndx].sh_type); 1502b03effaSXin LI error = EFTYPE; 15175d94ef6SJohn Birrell goto out; 1522b03effaSXin LI } 15375d94ef6SJohn Birrell 15475d94ef6SJohn Birrell /* Allocate memory to buffer the section header strings. */ 155ce47682cSMark Johnston shstrtab = malloc(shdr[hdr->e_shstrndx].sh_size, M_LINKER, M_WAITOK); 15675d94ef6SJohn Birrell 15775d94ef6SJohn Birrell /* Read the section header strings. */ 15875d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, shstrtab, 15975d94ef6SJohn Birrell shdr[hdr->e_shstrndx].sh_size, shdr[hdr->e_shstrndx].sh_offset, 1607abb0b09SMark Johnston UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, NULL, td)) != 0) 16175d94ef6SJohn Birrell goto out; 16275d94ef6SJohn Birrell 16375d94ef6SJohn Birrell /* Search for the section containing the CTF data. */ 16475d94ef6SJohn Birrell for (i = 0; i < hdr->e_shnum; i++) 16575d94ef6SJohn Birrell if (strcmp(".SUNW_ctf", shstrtab + shdr[i].sh_name) == 0) 16675d94ef6SJohn Birrell break; 16775d94ef6SJohn Birrell 16875d94ef6SJohn Birrell /* Check if the CTF section wasn't found. */ 1692b03effaSXin LI if (i >= hdr->e_shnum) { 1702b03effaSXin LI printf("%s(%d): module %s has no .SUNW_ctf section\n", 1712b03effaSXin LI __func__, __LINE__, lf->pathname); 1722b03effaSXin LI error = EFTYPE; 17375d94ef6SJohn Birrell goto out; 1742b03effaSXin LI } 17575d94ef6SJohn Birrell 17675d94ef6SJohn Birrell /* Read the CTF header. */ 177cab9382aSMark Johnston if ((error = vn_rdwr(UIO_READ, nd.ni_vp, &cth, sizeof(cth), 17875d94ef6SJohn Birrell shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, 1797abb0b09SMark Johnston NOCRED, NULL, td)) != 0) 18075d94ef6SJohn Birrell goto out; 18175d94ef6SJohn Birrell 182a5868885SJustin Hibbits /* Check the CTF magic number. */ 183cab9382aSMark Johnston if (cth.cth_magic != CTF_MAGIC) { 1842b03effaSXin LI printf("%s(%d): module %s has invalid format\n", 1852b03effaSXin LI __func__, __LINE__, lf->pathname); 1862b03effaSXin LI error = EFTYPE; 18775d94ef6SJohn Birrell goto out; 1882b03effaSXin LI } 18975d94ef6SJohn Birrell 1908dbae4ceSMark Johnston if (cth.cth_version != CTF_VERSION_2 && 1918dbae4ceSMark Johnston cth.cth_version != CTF_VERSION_3) { 1928dbae4ceSMark Johnston printf( 1938dbae4ceSMark Johnston "%s(%d): module %s CTF format has unsupported version %d\n", 194cab9382aSMark Johnston __func__, __LINE__, lf->pathname, cth.cth_version); 1952b03effaSXin LI error = EFTYPE; 19675d94ef6SJohn Birrell goto out; 1972b03effaSXin LI } 19875d94ef6SJohn Birrell 19975d94ef6SJohn Birrell /* Check if the data is compressed. */ 200cab9382aSMark Johnston if ((cth.cth_flags & CTF_F_COMPRESS) != 0) { 20175d94ef6SJohn Birrell /* 20275d94ef6SJohn Birrell * The last two fields in the CTF header are the offset 20375d94ef6SJohn Birrell * from the end of the header to the start of the string 204cab9382aSMark Johnston * data and the length of that string data. Use this 20575d94ef6SJohn Birrell * information to determine the decompressed CTF data 20675d94ef6SJohn Birrell * buffer required. 20775d94ef6SJohn Birrell */ 208cab9382aSMark Johnston sz = cth.cth_stroff + cth.cth_strlen + sizeof(cth); 20975d94ef6SJohn Birrell 21075d94ef6SJohn Birrell /* 21175d94ef6SJohn Birrell * Allocate memory for the compressed CTF data, including 21275d94ef6SJohn Birrell * the header (which isn't compressed). 21375d94ef6SJohn Birrell */ 214ce47682cSMark Johnston raw = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK); 21575d94ef6SJohn Birrell } else { 21675d94ef6SJohn Birrell /* 21775d94ef6SJohn Birrell * The CTF data is not compressed, so the ELF section 21875d94ef6SJohn Birrell * size is the same as the buffer size required. 21975d94ef6SJohn Birrell */ 22075d94ef6SJohn Birrell sz = shdr[i].sh_size; 22175d94ef6SJohn Birrell } 22275d94ef6SJohn Birrell 22375d94ef6SJohn Birrell /* 22428323addSBryan Drewery * Allocate memory to buffer the CTF data in its decompressed 22575d94ef6SJohn Birrell * form. 22675d94ef6SJohn Birrell */ 227ce47682cSMark Johnston ctftab = malloc(sz, M_LINKER, M_WAITOK); 22875d94ef6SJohn Birrell 22975d94ef6SJohn Birrell /* 23075d94ef6SJohn Birrell * Read the CTF data into the raw buffer if compressed, or 23175d94ef6SJohn Birrell * directly into the CTF buffer otherwise. 23275d94ef6SJohn Birrell */ 23375d94ef6SJohn Birrell if ((error = vn_rdwr(UIO_READ, nd.ni_vp, raw == NULL ? ctftab : raw, 23475d94ef6SJohn Birrell shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, 2357abb0b09SMark Johnston td->td_ucred, NOCRED, NULL, td)) != 0) 23675d94ef6SJohn Birrell goto out; 23775d94ef6SJohn Birrell 23875d94ef6SJohn Birrell /* Check if decompression is required. */ 23975d94ef6SJohn Birrell if (raw != NULL) { 240cb17f4a6SYoshihiro Ota uLongf destlen; 24175d94ef6SJohn Birrell int ret; 24275d94ef6SJohn Birrell 24375d94ef6SJohn Birrell /* 24475d94ef6SJohn Birrell * The header isn't compressed, so copy that into the 24575d94ef6SJohn Birrell * CTF buffer first. 24675d94ef6SJohn Birrell */ 247cab9382aSMark Johnston bcopy(&cth, ctftab, sizeof(cth)); 24875d94ef6SJohn Birrell 249cab9382aSMark Johnston destlen = sz - sizeof(cth); 250cab9382aSMark Johnston ret = uncompress(ctftab + sizeof(cth), &destlen, 251cab9382aSMark Johnston raw + sizeof(cth), shdr[i].sh_size - sizeof(cth)); 252cb17f4a6SYoshihiro Ota if (ret != Z_OK) { 253cab9382aSMark Johnston printf("%s(%d): zlib uncompress returned %d\n", 254cab9382aSMark Johnston __func__, __LINE__, ret); 25575d94ef6SJohn Birrell error = EIO; 25675d94ef6SJohn Birrell goto out; 25775d94ef6SJohn Birrell } 25875d94ef6SJohn Birrell } 25975d94ef6SJohn Birrell 26075d94ef6SJohn Birrell /* Got the CTF data! */ 26175d94ef6SJohn Birrell ef->ctftab = ctftab; 26275d94ef6SJohn Birrell ef->ctfcnt = shdr[i].sh_size; 26375d94ef6SJohn Birrell 26475d94ef6SJohn Birrell /* We'll retain the memory allocated for the CTF data. */ 26575d94ef6SJohn Birrell ctftab = NULL; 26675d94ef6SJohn Birrell 26775d94ef6SJohn Birrell /* Let the caller use the CTF data read. */ 26875d94ef6SJohn Birrell lc->ctftab = ef->ctftab; 26975d94ef6SJohn Birrell lc->ctfcnt = ef->ctfcnt; 27075d94ef6SJohn Birrell lc->symtab = ef->ddbsymtab; 27175d94ef6SJohn Birrell lc->strtab = ef->ddbstrtab; 27275d94ef6SJohn Birrell lc->strcnt = ef->ddbstrcnt; 27375d94ef6SJohn Birrell lc->nsym = ef->ddbsymcnt; 27475d94ef6SJohn Birrell lc->ctfoffp = (uint32_t **) &ef->ctfoff; 27575d94ef6SJohn Birrell lc->typoffp = (uint32_t **) &ef->typoff; 27675d94ef6SJohn Birrell lc->typlenp = &ef->typlen; 27775d94ef6SJohn Birrell 27875d94ef6SJohn Birrell out: 279b249ce48SMateusz Guzik VOP_UNLOCK(nd.ni_vp); 28075d94ef6SJohn Birrell vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 28175d94ef6SJohn Birrell 28275d94ef6SJohn Birrell if (hdr != NULL) 28375d94ef6SJohn Birrell free(hdr, M_LINKER); 28475d94ef6SJohn Birrell if (shdr != NULL) 28575d94ef6SJohn Birrell free(shdr, M_LINKER); 28675d94ef6SJohn Birrell if (shstrtab != NULL) 28775d94ef6SJohn Birrell free(shstrtab, M_LINKER); 28875d94ef6SJohn Birrell if (ctftab != NULL) 28975d94ef6SJohn Birrell free(ctftab, M_LINKER); 29075d94ef6SJohn Birrell if (raw != NULL) 29175d94ef6SJohn Birrell free(raw, M_LINKER); 29275d94ef6SJohn Birrell #else 29375d94ef6SJohn Birrell error = EOPNOTSUPP; 29475d94ef6SJohn Birrell #endif 29575d94ef6SJohn Birrell 29675d94ef6SJohn Birrell return (error); 29775d94ef6SJohn Birrell } 298c21bc6f3SBojan Novković 299c21bc6f3SBojan Novković static int 300c21bc6f3SBojan Novković link_elf_ctf_get_ddb(linker_file_t lf, linker_ctf_t *lc) 301c21bc6f3SBojan Novković { 302c21bc6f3SBojan Novković elf_file_t ef = (elf_file_t)lf; 303c21bc6f3SBojan Novković 304c21bc6f3SBojan Novković /* 305c21bc6f3SBojan Novković * Check whether CTF data was loaded or if a 306c21bc6f3SBojan Novković * previous loading attempt failed (ctfcnt == -1). 307c21bc6f3SBojan Novković */ 308c21bc6f3SBojan Novković if (ef->ctfcnt <= 0) { 309c21bc6f3SBojan Novković return (ENOENT); 310c21bc6f3SBojan Novković } 311c21bc6f3SBojan Novković 312c21bc6f3SBojan Novković lc->ctftab = ef->ctftab; 313c21bc6f3SBojan Novković lc->ctfcnt = ef->ctfcnt; 314c21bc6f3SBojan Novković lc->symtab = ef->ddbsymtab; 315c21bc6f3SBojan Novković lc->strtab = ef->ddbstrtab; 316c21bc6f3SBojan Novković lc->strcnt = ef->ddbstrcnt; 317c21bc6f3SBojan Novković lc->nsym = ef->ddbsymcnt; 318c21bc6f3SBojan Novković 319c21bc6f3SBojan Novković return (0); 320c21bc6f3SBojan Novković } 321c21bc6f3SBojan Novković 322c21bc6f3SBojan Novković static int 323c21bc6f3SBojan Novković link_elf_ctf_lookup_typename(linker_file_t lf, linker_ctf_t *lc, 324c21bc6f3SBojan Novković const char *typename) 325c21bc6f3SBojan Novković { 326c21bc6f3SBojan Novković if (link_elf_ctf_get_ddb(lf, lc)) 327c21bc6f3SBojan Novković return (ENOENT); 328c21bc6f3SBojan Novković 329*dc7ae2bcSMitchell Horne #ifdef DDB 330c21bc6f3SBojan Novković return (db_ctf_lookup_typename(lc, typename) ? 0 : ENOENT); 331*dc7ae2bcSMitchell Horne #else 332*dc7ae2bcSMitchell Horne return (ENOENT); 333*dc7ae2bcSMitchell Horne #endif 334c21bc6f3SBojan Novković } 335