freebsd-src/sys/kern/kern_ctf.c
Bojan Novković bdc903460b kern_ctf.c: Don't print out warning messages unconditionally
The kernel CTF loading routines print various warnings when attempting
to load CTF data from an ELF file. After the changes in c21bc6f3c2
those warnings are unnecessarily printed for each kernel module
that was compiled without CTF data.

The kernel linker already uses the bootverbose flag to conditionally
print CTF loading errors. This patch alters kern_ctf.c
routines to do the same.

Reported by:	Alexander@leidinger.net
Approved by:	markj (mentor)
Fixes: c21bc6f3c2 ("ddb: Add CTF-based pretty printing")
2024-03-29 20:32:18 +01:00

346 lines
9 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 John Birrell <jb@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/ctf.h>
#include <sys/kdb.h>
#include <sys/linker.h>
#include <ddb/db_ctf.h>
/*
* Note this file is included by both link_elf.c and link_elf_obj.c.
*/
#ifdef DDB_CTF
#include <contrib/zlib/zlib.h>
#endif
static int
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;
int i;
int nbytes;
size_t sz;
struct nameidata nd;
struct thread *td = curthread;
struct ctf_header cth;
#endif
int error = 0;
if (lf == NULL || lc == NULL)
return (EINVAL);
/* Set the defaults for no CTF present. That's not a crime! */
bzero(lc, sizeof(*lc));
#ifdef DDB_CTF
/*
* First check if we've tried to load CTF data previously and the
* CTF ELF section wasn't found. We flag that condition by setting
* ctfcnt to -1. See below.
*/
if (ef->ctfcnt < 0)
return (EFTYPE);
/* Now check if we've already loaded the CTF data.. */
if (ef->ctfcnt > 0) {
/* We only need to load once. */
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);
}
if (panicstr != NULL || kdb_active)
return (ENXIO);
/*
* We need to try reading the CTF data. Flag no CTF data present
* by default and if we actually succeed in reading it, we'll
* update ctfcnt to the number of bytes read.
*/
ef->ctfcnt = -1;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, lf->pathname);
flags = FREAD;
error = vn_open(&nd, &flags, 0, NULL);
if (error)
return (error);
NDFREE_PNBUF(&nd);
/* Allocate memory for the FLF header. */
hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK);
/* Read the ELF header. */
if ((error = vn_rdwr(UIO_READ, nd.ni_vp, hdr, sizeof(*hdr),
0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, NULL,
td)) != 0)
goto out;
/* Sanity check. */
if (!IS_ELF(*hdr)) {
error = ENOEXEC;
goto out;
}
nbytes = hdr->e_shnum * hdr->e_shentsize;
if (nbytes == 0 || hdr->e_shoff == 0 ||
hdr->e_shentsize != sizeof(Elf_Shdr)) {
error = ENOEXEC;
goto out;
}
/* Allocate memory for all the section headers */
shdr = malloc(nbytes, M_LINKER, M_WAITOK);
/* Read all the section headers */
if ((error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)shdr, nbytes,
hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
NULL, td)) != 0)
goto out;
/*
* We need to search for the CTF section by name, so if the
* section names aren't present, then we can't locate the
* .SUNW_ctf section containing the CTF data.
*/
if (hdr->e_shstrndx == 0 || shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
if (bootverbose) {
printf(
"%s(%d): module %s e_shstrndx is %d, sh_type is %d\n",
__func__, __LINE__, lf->pathname, hdr->e_shstrndx,
shdr[hdr->e_shstrndx].sh_type);
}
error = EFTYPE;
goto out;
}
/* Allocate memory to buffer the section header strings. */
shstrtab = malloc(shdr[hdr->e_shstrndx].sh_size, M_LINKER, M_WAITOK);
/* Read the section header strings. */
if ((error = vn_rdwr(UIO_READ, nd.ni_vp, shstrtab,
shdr[hdr->e_shstrndx].sh_size, shdr[hdr->e_shstrndx].sh_offset,
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, NULL, td)) != 0)
goto out;
/* Search for the section containing the CTF data. */
for (i = 0; i < hdr->e_shnum; i++)
if (strcmp(".SUNW_ctf", shstrtab + shdr[i].sh_name) == 0)
break;
/* Check if the CTF section wasn't found. */
if (i >= hdr->e_shnum) {
if (bootverbose) {
printf("%s(%d): module %s has no .SUNW_ctf section\n",
__func__, __LINE__, lf->pathname);
}
error = EFTYPE;
goto out;
}
/* Read the CTF header. */
if ((error = vn_rdwr(UIO_READ, nd.ni_vp, &cth, sizeof(cth),
shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
NOCRED, NULL, td)) != 0)
goto out;
/* Check the CTF magic number. */
if (cth.cth_magic != CTF_MAGIC) {
if (bootverbose) {
printf("%s(%d): module %s has invalid format\n",
__func__, __LINE__, lf->pathname);
}
error = EFTYPE;
goto out;
}
if (cth.cth_version != CTF_VERSION_2 &&
cth.cth_version != CTF_VERSION_3) {
if (bootverbose) {
printf(
"%s(%d): module %s CTF format has unsupported version %d\n",
__func__, __LINE__, lf->pathname, cth.cth_version);
}
error = EFTYPE;
goto out;
}
/* Check if the data is compressed. */
if ((cth.cth_flags & CTF_F_COMPRESS) != 0) {
/*
* 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. Use this
* information to determine the decompressed CTF data
* buffer required.
*/
sz = cth.cth_stroff + cth.cth_strlen + sizeof(cth);
/*
* Allocate memory for the compressed CTF data, including
* the header (which isn't compressed).
*/
raw = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK);
} 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 its decompressed
* form.
*/
ctftab = malloc(sz, M_LINKER, M_WAITOK);
/*
* 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, NULL, td)) != 0)
goto out;
/* Check if decompression is required. */
if (raw != NULL) {
uLongf destlen;
int ret;
/*
* The header isn't compressed, so copy that into the
* CTF buffer first.
*/
bcopy(&cth, ctftab, sizeof(cth));
destlen = sz - sizeof(cth);
ret = uncompress(ctftab + sizeof(cth), &destlen,
raw + sizeof(cth), shdr[i].sh_size - sizeof(cth));
if (ret != Z_OK) {
if (bootverbose) {
printf("%s(%d): zlib uncompress returned %d\n",
__func__, __LINE__, ret);
}
error = EIO;
goto out;
}
}
/* Got the CTF data! */
ef->ctftab = ctftab;
ef->ctfcnt = shdr[i].sh_size;
/* We'll retain the memory allocated for the CTF data. */
ctftab = NULL;
/* Let the caller use the CTF data read. */
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);
vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
if (hdr != NULL)
free(hdr, M_LINKER);
if (shdr != NULL)
free(shdr, M_LINKER);
if (shstrtab != NULL)
free(shstrtab, M_LINKER);
if (ctftab != NULL)
free(ctftab, M_LINKER);
if (raw != NULL)
free(raw, M_LINKER);
#else
error = EOPNOTSUPP;
#endif
return (error);
}
static int
link_elf_ctf_get_ddb(linker_file_t lf, linker_ctf_t *lc)
{
elf_file_t ef = (elf_file_t)lf;
/*
* Check whether CTF data was loaded or if a
* previous loading attempt failed (ctfcnt == -1).
*/
if (ef->ctfcnt <= 0) {
return (ENOENT);
}
lc->ctftab = ef->ctftab;
lc->ctfcnt = ef->ctfcnt;
lc->symtab = ef->ddbsymtab;
lc->strtab = ef->ddbstrtab;
lc->strcnt = ef->ddbstrcnt;
lc->nsym = ef->ddbsymcnt;
return (0);
}
static int
link_elf_ctf_lookup_typename(linker_file_t lf, linker_ctf_t *lc,
const char *typename)
{
if (link_elf_ctf_get_ddb(lf, lc))
return (ENOENT);
#ifdef DDB
return (db_ctf_lookup_typename(lc, typename) ? 0 : ENOENT);
#else
return (ENOENT);
#endif
}