Module Name: src Committed By: darran Date: Fri Mar 12 21:43:11 UTC 2010
Modified Files: src/sys/conf: files src/sys/kern: kern_ksyms.c src/sys/lib/libsa: loadfile_elf32.c src/sys/sys: ksyms.h Added Files: src/sys/kern: kern_ctf.c src/sys/sys: kern_ctf.h Log Message: DTrace: Add support for CTF sections in the netbsd elf image, load these at boot. Add a ksyms_mod_foreach() function to iterate a callback function over the set of elf symbols for a specific module (netbsd included). Add kern_ctf.c and mod_ctf_get() to allow the retrieval and decompression of CTF sections for a specific module. To generate a diff of this commit: cvs rdiff -u -r1.980 -r1.981 src/sys/conf/files cvs rdiff -u -r0 -r1.1 src/sys/kern/kern_ctf.c cvs rdiff -u -r1.55 -r1.56 src/sys/kern/kern_ksyms.c cvs rdiff -u -r1.24 -r1.25 src/sys/lib/libsa/loadfile_elf32.c cvs rdiff -u -r0 -r1.1 src/sys/sys/kern_ctf.h cvs rdiff -u -r1.24 -r1.25 src/sys/sys/ksyms.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/conf/files diff -u src/sys/conf/files:1.980 src/sys/conf/files:1.981 --- src/sys/conf/files:1.980 Wed Mar 3 13:39:57 2010 +++ src/sys/conf/files Fri Mar 12 21:43:11 2010 @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.980 2010/03/03 13:39:57 tsutsui Exp $ +# $NetBSD: files,v 1.981 2010/03/12 21:43:11 darran Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20090313 @@ -1424,6 +1424,7 @@ file kern/kern_condvar.c file kern/kern_core.c coredump file kern/kern_cpu.c +file kern/kern_ctf.c file kern/kern_descrip.c file kern/kern_event.c file kern/kern_exec.c Index: src/sys/kern/kern_ksyms.c diff -u src/sys/kern/kern_ksyms.c:1.55 src/sys/kern/kern_ksyms.c:1.56 --- src/sys/kern/kern_ksyms.c:1.55 Mon Mar 1 22:27:07 2010 +++ src/sys/kern/kern_ksyms.c Fri Mar 12 21:43:11 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_ksyms.c,v 1.55 2010/03/01 22:27:07 darran Exp $ */ +/* $NetBSD: kern_ksyms.c,v 1.56 2010/03/12 21:43:11 darran Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -71,11 +71,12 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.55 2010/03/01 22:27:07 darran Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.56 2010/03/12 21:43:11 darran Exp $"); #if defined(_KERNEL) && defined(_KERNEL_OPT) #include "opt_ddb.h" #include "opt_ddbparam.h" /* for SYMTAB_SPACE */ +#include "opt_dtrace.h" #endif #define _KSYMS_PRIVATE @@ -98,6 +99,13 @@ #include "ksyms.h" +#define KSYMS_MAX_ID 65536 +#ifdef KDTRACE_HOOKS +static uint32_t ksyms_nmap[KSYMS_MAX_ID]; /* sorted symbol table map */ +#else +static uint32_t *ksyms_nmap = NULL; +#endif + static int ksyms_maxlen; static bool ksyms_isopen; static bool ksyms_initted; @@ -124,6 +132,7 @@ int ksyms_symsz; int ksyms_strsz; +int ksyms_ctfsz; TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs = TAILQ_HEAD_INITIALIZER(ksyms_symtabs); static struct ksyms_symtab kernel_symtab; @@ -264,11 +273,21 @@ static void addsymtab(const char *name, void *symstart, size_t symsize, void *strstart, size_t strsize, struct ksyms_symtab *tab, - void *newstart) + void *newstart, void *ctfstart, size_t ctfsize, uint32_t *nmap) { Elf_Sym *sym, *nsym, ts; int i, j, n, nglob; char *str; + int nsyms = symsize / sizeof(Elf_Sym); + + /* sanity check for pre-malloc map table used during startup */ + if ((nmap == ksyms_nmap) && (nsyms >= KSYMS_MAX_ID)) { + printf("kern_ksyms: ERROR %d > %d, increase KSYMS_MAX_ID\n", + nsyms, KSYMS_MAX_ID); + + /* truncate for now */ + nsyms = KSYMS_MAX_ID-1; + } tab->sd_symstart = symstart; tab->sd_symsize = symsize; @@ -279,18 +298,31 @@ tab->sd_maxsym = 0; tab->sd_usroffset = 0; tab->sd_gone = false; + tab->sd_ctfstart = ctfstart; + tab->sd_ctfsize = ctfsize; + tab->sd_nmap = nmap; + tab->sd_nmapsize = nsyms; #ifdef KSYMS_DEBUG printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n", newstart, symstart, symsize, strstart, strsize, tab->sd_strstart + tab->sd_strsize); #endif + if (nmap) { + memset(nmap, 0, nsyms * sizeof(uint32_t)); + } + /* Pack symbol table by removing all file name references. */ sym = tab->sd_symstart; nsym = (Elf_Sym *)newstart; str = tab->sd_strstart; nglob = 0; - for (i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) { + for (i = n = 0; i < nsyms; i++) { + + /* This breaks CTF mapping, so don't do it when + * DTrace is enabled + */ +#ifndef KDTRACE_HOOKS /* * Remove useless symbols. * Should actually remove all typeless symbols. @@ -308,9 +340,19 @@ if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0) continue; /* XXX */ +#endif /* Save symbol. Set it as an absolute offset */ nsym[n] = sym[i]; + + if (nmap != NULL) { + /* Save the size, replace it with the symbol id so + * the mapping can be done after the cleanup and sort. + */ + nmap[i] = nsym[n].st_size; + nsym[n].st_size = i+1; /* zero is reserved */ + } + nsym[n].st_shndx = SHBSS; j = strlen(nsym[n].st_name + str) + 1; if (j > ksyms_maxlen) @@ -335,6 +377,25 @@ if (kheapsort(nsym, n, sizeof(Elf_Sym), addsymtab_compar, &ts) != 0) panic("addsymtab"); + /* + * Build the mapping from original symbol id to new symbol table. + * Deleted symbols will have a zero map, indices will be one based + * instead of zero based. + * Resulting map is sd_nmap[original_index] = new_index + 1 + */ + if (nmap != NULL) { + int new; + for (new=0; new<n; new++) { + uint32_t orig = nsym[new].st_size - 1; + uint32_t size = nmap[orig]; + + nmap[orig] = new + 1; + + /* restore the size */ + nsym[new].st_size = size; + } + } + /* ksymsread() is unlocked, so membar. */ membar_producer(); TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue); @@ -353,6 +414,9 @@ char *symstart = NULL, *strstart = NULL; size_t strsize = 0; Elf_Ehdr *ehdr; + char *ctfstart = NULL; + size_t ctfsize = 0; + char *shstr = NULL; if (symsize <= 0) { printf("[ Kernel symbol table missing! ]\n"); @@ -397,10 +461,31 @@ break; } + /* Find the CTF section */ + shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff); + if (ehdr->e_shstrndx != 0) { + shstr = (uint8_t*)start + shdr[ehdr->e_shstrndx].sh_offset; + for (i = 1; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_PROGBITS) + continue; + if (strncmp(".SUNW_ctf", &shstr[shdr[i].sh_name] ,10) != 0) + continue; + ctfstart = (uint8_t *)start + shdr[i].sh_offset; + ctfsize = shdr[i].sh_size; + ksyms_ctfsz = ctfsize; +#ifdef DEBUG + aprint_normal("Found CTF at 0x%x, size 0x%x\n", + (uint32_t)ctfstart, ctfsize); +#endif + break; + } + } + if (!ksyms_verify(symstart, strstart)) return; + addsymtab("netbsd", symstart, symsize, strstart, strsize, - &kernel_symtab, start); + &kernel_symtab, start, ctfstart, ctfsize, ksyms_nmap); #ifdef DEBUG aprint_normal("Loaded initial symtab at %p, strtab at %p, # entries %ld\n", @@ -427,7 +512,7 @@ ksyms_hdr_init(ehdr); addsymtab("netbsd", symstart, symsize, strstart, strsize, - &kernel_symtab, symstart); + &kernel_symtab, symstart, NULL, 0, ksyms_nmap); } /* @@ -479,6 +564,73 @@ return rc; } +struct ksyms_symtab * +ksyms_get_mod(const char *mod) +{ + struct ksyms_symtab *st; + + mutex_enter(&ksyms_lock); + TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { + if (__predict_false(st->sd_gone)) + continue; + if (mod != NULL && strcmp(st->sd_name, mod)) + continue; + break; + } + mutex_exit(&ksyms_lock); + + return st; +} + + +/* + * ksyms_mod_foreach() + * + * Iterate over the symbol table of the specified module, calling the callback + * handler for each symbol. Stop iterating if the handler return is non-zero. + * + */ + +int +ksyms_mod_foreach(const char *mod, ksyms_callback_t callback, void *opaque) +{ + struct ksyms_symtab *st; + Elf_Sym *sym, *maxsym; + char *str; + int symindx; + + if (!ksyms_initted) + return ENOENT; + + mutex_enter(&ksyms_lock); + + /* find the module */ + TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { + if (__predict_false(st->sd_gone)) + continue; + if (mod != NULL && strcmp(st->sd_name, mod)) + continue; + + sym = st->sd_symstart; + str = st->sd_strstart - st->sd_usroffset; + + /* now iterate through the symbols */ + maxsym = sym + st->sd_symsize / sizeof(Elf_Sym); + for (symindx=0; sym < maxsym; sym++,symindx++) { + if (callback(str + sym->st_name, symindx, + (void *)sym->st_value, + sym->st_size, + sym->st_info, + opaque) != 0) { + break; + } + } + } + mutex_exit(&ksyms_lock); + + return 0; +} + /* * Get "mod" and "symbol" associated with an address. * Returns 0 if success or ENOENT if no such entry. @@ -548,7 +700,8 @@ st = kmem_zalloc(sizeof(*st), KM_SLEEP); mutex_enter(&ksyms_lock); - addsymtab(name, symstart, symsize, strstart, strsize, st, symstart); + addsymtab(name, symstart, symsize, strstart, strsize, st, symstart, + NULL, 0, NULL); mutex_exit(&ksyms_lock); } @@ -722,6 +875,14 @@ ksyms_hdr.kh_shdr[SHBSS].sh_addralign = PAGE_SIZE; ksyms_hdr.kh_shdr[SHBSS].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + /* Sixth section header; ".SUNW_ctf" */ + ksyms_hdr.kh_shdr[SHCTF].sh_name = 32; /* Section 6 offset */ + ksyms_hdr.kh_shdr[SHCTF].sh_type = SHT_PROGBITS; +/* ksyms_hdr.kh_shdr[SHCTF].sh_offset = filled in at open */ +/* ksyms_hdr.kh_shdr[SHCTF].sh_size = filled in at open */ + ksyms_hdr.kh_shdr[SHCTF].sh_link = SYMTAB; /* Corresponding symtab */ + ksyms_hdr.kh_shdr[SHCTF].sh_addralign = sizeof(char); + /* Set section names */ strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab", sizeof(ksyms_hdr.kh_strtab) - 1); @@ -731,6 +892,8 @@ sizeof(ksyms_hdr.kh_strtab) - 17); strlcpy(&ksyms_hdr.kh_strtab[27], ".bss", sizeof(ksyms_hdr.kh_strtab) - 27); + strlcpy(&ksyms_hdr.kh_strtab[32], ".SUNW_ctf", + sizeof(ksyms_hdr.kh_strtab) - 32); } static int @@ -750,6 +913,9 @@ ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz + ksyms_hdr.kh_shdr[SYMTAB].sh_offset; ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz; + ksyms_hdr.kh_shdr[SHCTF].sh_offset = ksyms_strsz + + ksyms_hdr.kh_shdr[STRTAB].sh_offset; + ksyms_hdr.kh_shdr[SHCTF].sh_size = ksyms_ctfsz; ksyms_isopen = true; mutex_exit(&ksyms_lock); @@ -784,7 +950,7 @@ static int ksymsread(dev_t dev, struct uio *uio, int ioflag) { - struct ksyms_symtab *st; + struct ksyms_symtab *st, *cst; size_t filepos, inpos, off; int error; @@ -835,6 +1001,24 @@ filepos += st->sd_strsize; } + /* + * Copy out the CTF table. + */ + cst = TAILQ_FIRST(&ksyms_symtabs); + if (cst->sd_ctfstart != NULL) { + if (uio->uio_resid == 0) + return 0; + if (uio->uio_offset <= cst->sd_ctfsize + filepos) { + inpos = uio->uio_offset - filepos; + error = uiomove((char *)cst->sd_ctfstart + inpos, + cst->sd_ctfsize - inpos, uio); + if (error != 0) + return error; + } + filepos += cst->sd_ctfsize; + } + + return 0; } Index: src/sys/lib/libsa/loadfile_elf32.c diff -u src/sys/lib/libsa/loadfile_elf32.c:1.24 src/sys/lib/libsa/loadfile_elf32.c:1.25 --- src/sys/lib/libsa/loadfile_elf32.c:1.24 Thu Sep 25 20:59:38 2008 +++ src/sys/lib/libsa/loadfile_elf32.c Fri Mar 12 21:43:11 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: loadfile_elf32.c,v 1.24 2008/09/25 20:59:38 christos Exp $ */ +/* $NetBSD: loadfile_elf32.c,v 1.25 2010/03/12 21:43:11 darran Exp $ */ /*- * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. @@ -271,6 +271,8 @@ uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1]; uint8_t desc[ELF_NOTE_NETBSD_DESCSZ]; } note; + char *shstr = NULL; + int boot_load_ctf=1; /* some ports dont use the offset */ offset = offset; @@ -406,13 +408,66 @@ #endif /* ! _STANDALONE */ /* + * First load the section names section. + */ + if (boot_load_ctf && (elf->e_shstrndx != 0)) { + if (lseek(fd, shp[elf->e_shstrndx].sh_offset, + SEEK_SET) == -1) { + WARN(("lseek symbols")); + goto freeshp; + } + nr = READ(fd, maxp, shp[elf->e_shstrndx].sh_size); + if (nr == -1) { + WARN(("read symbols")); + goto freeshp; + } + if (nr != (ssize_t)shp[elf->e_shstrndx].sh_size) { + errno = EIO; + WARN(("read symbols")); + goto freeshp; + } + + shstr = ALLOC(shp[elf->e_shstrndx].sh_size); + if (lseek(fd, shp[elf->e_shstrndx].sh_offset, + SEEK_SET) == -1) { + WARN(("lseek symbols")); + goto freeshp; + } + nr = read(fd, shstr, shp[elf->e_shstrndx].sh_size); + if (nr == -1) { + WARN(("read symbols")); + goto freeshp; + } + + shp[elf->e_shstrndx].sh_offset = maxp - elfp; + maxp += roundup(shp[elf->e_shstrndx].sh_size, ELFROUND); + } + + /* * Now load the symbol sections themselves. Make sure * the sections are aligned. Don't bother with any * string table that isn't referenced by a symbol * table. */ for (first = 1, i = 0; i < elf->e_shnum; i++) { + if (i == elf->e_shstrndx) { + /* already loaded this section */ + continue; + } switch (shp[i].sh_type) { + case SHT_PROGBITS: + if (boot_load_ctf && shstr) { + /* got a CTF section? */ + if (strncmp(".SUNW_ctf", + &shstr[shp[i].sh_name], + 10) == 0) { + goto havesym; + } + } + + /* Not loading this, so zero out the offset. */ + shp[i].sh_offset = 0; + break; case SHT_STRTAB: for (j = 0; j < elf->e_shnum; j++) if (shp[j].sh_type == SHT_SYMTAB && @@ -479,8 +534,6 @@ shp[i].sh_offset = 0; break; } - /* Since we don't load .shstrtab, zero the name. */ - shp[i].sh_name = 0; } if (flags & LOAD_SYM) { #ifndef _STANDALONE @@ -496,6 +549,10 @@ } DEALLOC(shp, sz); } + + if (shstr) { + DEALLOC(shstr, shp[elf->e_shstrndx].sh_size); + } /* * Frob the copied ELF header to give information relative @@ -506,7 +563,6 @@ elf->e_shoff = sizeof(Elf_Ehdr); elf->e_phentsize = 0; elf->e_phnum = 0; - elf->e_shstrndx = SHN_UNDEF; externalize_ehdr(elf->e_ident[EI_DATA], elf); BCOPY(elf, elfp, sizeof(*elf)); internalize_ehdr(elf->e_ident[EI_DATA], elf); Index: src/sys/sys/ksyms.h diff -u src/sys/sys/ksyms.h:1.24 src/sys/sys/ksyms.h:1.25 --- src/sys/sys/ksyms.h:1.24 Mon Mar 1 21:10:13 2010 +++ src/sys/sys/ksyms.h Fri Mar 12 21:43:10 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ksyms.h,v 1.24 2010/03/01 21:10:13 darran Exp $ */ +/* $NetBSD: ksyms.h,v 1.25 2010/03/12 21:43:10 darran Exp $ */ /* * Copyright (c) 2001, 2003 Anders Magnusson (ra...@ludd.luth.se). @@ -49,6 +49,8 @@ bool sd_gone; /* dead but around for open() */ void *sd_ctfstart; /* Address of CTF contents */ int sd_ctfsize; /* Size in bytes of CTF contents */ + uint32_t *sd_nmap; /* Name map for sorted symbols */ + int sd_nmapsize; /* Total span of map */ }; /* @@ -101,12 +103,18 @@ #define KSYMS_PROC 0100 /* Procedures only */ #define KSYMS_ANY 0200 /* Also local symbols (DDB use only) */ +typedef int (*ksyms_callback_t)(const char *, int, void *, + uint32_t, int, void *); + /* * Prototypes */ + int ksyms_getname(const char **, const char **, vaddr_t, int); int ksyms_getval(const char *, const char *, unsigned long *, int); int ksyms_getval_unlocked(const char *, const char *, unsigned long *, int); +struct ksyms_symtab *ksyms_get_mod(const char *); +int ksyms_mod_foreach(const char *mod, ksyms_callback_t, void *); int ksyms_addsymtab(const char *, void *, vsize_t, char *, vsize_t); int ksyms_delsymtab(const char *); void ksyms_init(void); Added files: Index: src/sys/kern/kern_ctf.c diff -u /dev/null src/sys/kern/kern_ctf.c:1.1 --- /dev/null Fri Mar 12 21:43:11 2010 +++ src/sys/kern/kern_ctf.c Fri Mar 12 21:43:11 2010 @@ -0,0 +1,229 @@ +/* $NetBSD: kern_ctf.c,v 1.1 2010/03/12 21:43:11 darran Exp $ */ +/*- + * Copyright (c) 2008 John Birrell <j...@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_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) { + goto out; + } + + /* Check the CTF magic number. (XXX check for big endian!) */ + if (ctfaddr[0] != 0xf1 || ctfaddr[1] != 0xcf) { + goto out; + } + + /* Check if version 2. */ + if (ctfaddr[2] != 2) + 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); +} Index: src/sys/sys/kern_ctf.h diff -u /dev/null src/sys/sys/kern_ctf.h:1.1 --- /dev/null Fri Mar 12 21:43:11 2010 +++ src/sys/sys/kern_ctf.h Fri Mar 12 21:43:10 2010 @@ -0,0 +1,53 @@ +/* $NetBSD: kern_ctf.h,v 1.1 2010/03/12 21:43:10 darran Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _SYS_CTF_H_ +#define _SYS_CTF_H_ + +/* + * Modules CTF section + */ +typedef struct mod_ctf { + const uint8_t *ctftab; /* Decompressed CTF data. */ + int ctfcnt; /* Number of CTF data bytes. */ + const Elf_Sym *symtab; /* Ptr to the symbol table. */ + int nsym; /* Number of symbols. */ + uint32_t *nmap; /* symbol id map */ + int nmapsize; /* Span of id map */ + const char *strtab; /* Ptr to the string table. */ + int strcnt; /* Number of string bytes. */ + uint32_t *ctfoffp; /* Ptr to array of obj/fnc offsets. */ + uint32_t *typoffp; /* Ptr to array of type offsets. */ + long typlen; /* number of type data entries. */ + int ctfalloc; /* ctftab is alloced */ +} mod_ctf_t; + +int +mod_ctf_get(struct module *, mod_ctf_t *); + +#endif