[BACK]Return to kern_ctf.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

File: [cvs.NetBSD.org] / src / sys / kern / kern_ctf.c (download)

Revision 1.3, Mon May 3 09:51:36 2010 UTC (13 years, 11 months ago) by darran
Branch: MAIN
CVS Tags: yamt-pagecache-tag8, yamt-pagecache-base9, yamt-pagecache-base8, yamt-pagecache-base7, yamt-pagecache-base6, yamt-pagecache-base5, yamt-pagecache-base4, yamt-pagecache-base3, yamt-pagecache-base2, yamt-pagecache-base, yamt-pagecache, yamt-nfs-mp-base11, yamt-nfs-mp-base10, uebayasi-xip-base4, uebayasi-xip-base3, uebayasi-xip-base2, tls-maxphys-base, tls-earlyentropy-base, tls-earlyentropy, rmind-uvmplock-nbase, rmind-uvmplock-base, rmind-smpnet-nbase, rmind-smpnet-base, rmind-smpnet, riastradh-xf86-video-intel-2-7-1-pre-2-21-15, riastradh-drm2-base3, riastradh-drm2-base2, riastradh-drm2-base1, riastradh-drm2-base, riastradh-drm2, netbsd-7-nhusb-base-20170116, netbsd-7-nhusb-base, netbsd-7-nhusb, netbsd-7-base, netbsd-7-2-RELEASE, netbsd-7-1-RELEASE, netbsd-7-1-RC2, netbsd-7-1-RC1, netbsd-7-1-2-RELEASE, netbsd-7-1-1-RELEASE, netbsd-7-1, netbsd-7-0-RELEASE, netbsd-7-0-RC3, netbsd-7-0-RC2, netbsd-7-0-RC1, netbsd-7-0-2-RELEASE, netbsd-7-0-1-RELEASE, netbsd-7-0, netbsd-7, netbsd-6-base, netbsd-6-1-RELEASE, netbsd-6-1-RC4, netbsd-6-1-RC3, netbsd-6-1-RC2, netbsd-6-1-RC1, netbsd-6-1-5-RELEASE, netbsd-6-1-4-RELEASE, netbsd-6-1-3-RELEASE, netbsd-6-1-2-RELEASE, netbsd-6-1-1-RELEASE, netbsd-6-1, netbsd-6-0-RELEASE, netbsd-6-0-RC2, netbsd-6-0-RC1, netbsd-6-0-6-RELEASE, netbsd-6-0-5-RELEASE, netbsd-6-0-4-RELEASE, netbsd-6-0-3-RELEASE, netbsd-6-0-2-RELEASE, netbsd-6-0-1-RELEASE, netbsd-6-0, netbsd-6, matt-nb6-plus-nbase, matt-nb6-plus-base, matt-nb6-plus, matt-mips64-premerge-20101231, khorben-n900, jruoho-x86intr-base, jruoho-x86intr, jmcneill-usbmp-pre-base2, jmcneill-usbmp-base9, jmcneill-usbmp-base8, jmcneill-usbmp-base7, jmcneill-usbmp-base6, jmcneill-usbmp-base5, jmcneill-usbmp-base4, jmcneill-usbmp-base3, jmcneill-usbmp-base2, jmcneill-usbmp-base10, jmcneill-usbmp-base, jmcneill-usbmp, jmcneill-audiomp3-base, jmcneill-audiomp3, cherry-xenmp-base, cherry-xenmp, bouyer-quota2-nbase, bouyer-quota2-base, bouyer-quota2, agc-symver-base, agc-symver
Branch point for: yamt-nfs-mp, tls-maxphys
Changes since 1.2: +10 -4 lines

DTrace: Fix several bugs where the mod_ctf_get() function could return
success even though no CTF section was present in the kernel or module.
This fixes the panic that several people saw when trying out the FBT
provider without updating /boot or missing a CTF section in /netbsd.

/*	$NetBSD: kern_ctf.c,v 1.3 2010/05/03 09:51:36 darran Exp $	*/
/*-
 * 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.
 *
 * $FreeBSD: src/sys/kern/kern_ctf.c,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $
 */

#define ELFSIZE ARCH_ELFSIZE
#include <sys/module.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/kmem.h>
#include <sys/malloc.h>
#include <sys/kobj_impl.h>
#include <sys/kobj.h>
#include <sys/kern_ctf.h>

#define _KSYMS_PRIVATE
#include <sys/ksyms.h>

#include <net/zlib.h>

/*
 * 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

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);
}

int
mod_ctf_get(struct module *mod, mod_ctf_t *mc)
{
	mod_ctf_t *cmc;
	struct ksyms_symtab *st; 
	void * ctftab = NULL;
	size_t sz;
	int error = 0;
	int compressed = 0;

	void *ctfbuf = NULL;
	uint8_t *ctfaddr;
	size_t ctfsize;

	if (mc == NULL) {
		return EINVAL;
	}

	/* Set the defaults for no CTF present. That's not a crime! */
	memset(mc, 0, sizeof(*mc));

	/* cached mc? */
	if (mod->mod_ctf != NULL) {
		cmc = mod->mod_ctf;
		*mc = *cmc;
		return (0);
	}

	st = ksyms_get_mod(mod->mod_info->mi_name);

	if (st != NULL) {
		mc->nmap     = st->sd_nmap;
		mc->nmapsize = st->sd_nmapsize;
	}

	if (mod->mod_kobj == NULL) {
	    	/* no kobj entry, try building from ksyms list */
		if (st == NULL) {
			return ENOENT;
		}

		ctfaddr = st->sd_ctfstart;
		ctfsize = st->sd_ctfsize;

		mc->symtab = st->sd_symstart;
		mc->strtab = st->sd_strstart;
		mc->strcnt = 0;		/* XXX TBD */
		mc->nsym   = st->sd_symsize / sizeof(Elf_Sym);
	} else {
		if (kobj_find_section(mod->mod_kobj, ".SUNW_ctf", (void **)&ctfaddr, &ctfsize)) {
			return ENOENT;
		}

		mc->symtab = mod->mod_kobj->ko_symtab;
		mc->strtab = mod->mod_kobj->ko_strtab;
		mc->strcnt = 0;		/* XXX TBD */
		mc->nsym   = mod->mod_kobj->ko_symcnt;
	}

	if (ctfaddr == NULL) {
	    	error = ENOENT;
		goto out;
	}

	/* Check the CTF magic number. (XXX check for big endian!) */
	if (ctfaddr[0] != 0xf1 || ctfaddr[1] != 0xcf) {
	    	error = EINVAL;
		goto out;
	}

	/* Check if version 2. */
	if (ctfaddr[2] != 2) {
	    	error = EINVAL;
		goto out;
	}

	/* Check if the data is compressed. */
	if ((ctfaddr[3] & 0x1) != 0) {
		uint32_t *u32 = (uint32_t *) ctfaddr;

		/*
		 * 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] +
		    CTF_HDR_SIZE;

		compressed = 1;
	} else {
		/*
		 * The CTF data is not compressed, so the ELF section
		 * size is the same as the buffer size required.
		 */
		sz = ctfsize;
	}

	/*
	 * Allocate memory to buffer the CTF data in it's decompressed
	 * form.
	 */
	if (compressed) {
		if ((ctfbuf = malloc(sz, M_TEMP, M_WAITOK)) == NULL) {
			error = ENOMEM;
			goto out;
		}
		ctftab = ctfbuf;
		mc->ctfalloc = 1;
	} else {
		ctftab = (void *)ctfaddr;
	}

	/* Check if decompression is required. */
	if (compressed) {
		z_stream zs;
		int ret;

		/*
		 * The header isn't compressed, so copy that into the
		 * CTF buffer first.
		 */
		memcpy(ctftab, ctfaddr, CTF_HDR_SIZE);

		/* Initialise the zlib structure. */
		memset(&zs, 0, sizeof(zs));
		zs.zalloc = z_alloc;
		zs.zfree = z_free;

		if (inflateInit2(&zs, MAX_WBITS) != Z_OK) {
			error = EIO;
			goto out;
		}

		zs.avail_in = ctfsize - CTF_HDR_SIZE;
		zs.next_in = ((uint8_t *) ctfaddr) + CTF_HDR_SIZE;
		zs.avail_out = sz - CTF_HDR_SIZE;
		zs.next_out = ((uint8_t *) ctftab) + CTF_HDR_SIZE;
		inflateReset(&zs);
		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! */
	mc->ctftab = ctftab;
	mc->ctfcnt = ctfsize;

	/* cache it */
	cmc = kmem_alloc(sizeof(mod_ctf_t), KM_SLEEP);

	*cmc = *mc;
	mod->mod_ctf = cmc;

	/* We'll retain the memory allocated for the CTF data. */
	ctfbuf = NULL;

out:
	if (ctfbuf != NULL)
		free(ctfbuf, M_TEMP);

	return (error);
}