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

Reply via email to