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 ([email protected]).
@@ -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 <[email protected]>
+ * 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