subr_stack.c revision 159022
119370Spst/*-
298944Sobrien * Copyright (c) 2005 Antoine Brodin
3130803Smarcel * All rights reserved.
419370Spst *
519370Spst * Redistribution and use in source and binary forms, with or without
698944Sobrien * modification, are permitted provided that the following conditions
719370Spst * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer in the
1219370Spst *    documentation and/or other materials provided with the distribution.
1398944Sobrien *
1498944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1598944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1698944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1719370Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1898944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1998944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2098944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2198944Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2219370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24130803Smarcel * SUCH DAMAGE.
2519370Spst */
2619370Spst
2719370Spst#include <sys/cdefs.h>
2819370Spst__FBSDID("$FreeBSD: head/sys/kern/subr_stack.c 159022 2006-05-28 22:15:28Z kris $");
2919370Spst
3019370Spst#include <sys/param.h>
3119370Spst#include <sys/kernel.h>
3219370Spst#ifdef KTR
3319370Spst#include <sys/ktr.h>
3419370Spst#endif
3519370Spst#include <sys/linker.h>
3698944Sobrien#include <sys/malloc.h>
3719370Spst#include <sys/sbuf.h>
3819370Spst#include <sys/stack.h>
3919370Spst#include <sys/systm.h>
4019370Spst
4146283SdfrMALLOC_DEFINE(M_STACK, "stack", "Stack Traces");
4246283Sdfr
4346283Sdfrstatic void stack_symbol(vm_offset_t pc, const char **name, long *offset);
44130803Smarcel
4598944Sobrienstruct stack *
4698944Sobrienstack_create(void)
4719370Spst{
4898944Sobrien	struct stack *st;
4919370Spst
5098944Sobrien	st = malloc(sizeof *st, M_STACK, M_WAITOK | M_ZERO);
5119370Spst	return (st);
52130803Smarcel}
53130803Smarcel
5446283Sdfrvoid
5598944Sobrienstack_destroy(struct stack *st)
5698944Sobrien{
5798944Sobrien
5819370Spst	free(st, M_STACK);
5919370Spst}
6019370Spst
6119370Spstint
6219370Spststack_put(struct stack *st, vm_offset_t pc)
6319370Spst{
6419370Spst
6598944Sobrien	if (st->depth < STACK_MAX) {
6698944Sobrien		st->pcs[st->depth++] = pc;
6719370Spst		return (0);
68130803Smarcel	} else
6919370Spst		return (-1);
70130803Smarcel}
7119370Spst
7219370Spstvoid
7319370Spststack_copy(struct stack *src, struct stack *dst)
7419370Spst{
7519370Spst
7619370Spst	*dst = *src;
7719370Spst}
7819370Spst
7998944Sobrienvoid
8098944Sobrienstack_zero(struct stack *st)
8119370Spst{
8219370Spst
8319370Spst	bzero(st, sizeof *st);
8419370Spst}
8519370Spst
8619370Spstvoid
8719370Spststack_print(struct stack *st)
8819370Spst{
89130803Smarcel	const char *name;
90130803Smarcel	long offset;
9119370Spst	int i;
9246283Sdfr
9346283Sdfr	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
9446283Sdfr	for (i = 0; i < st->depth; i++) {
9519370Spst		stack_symbol(st->pcs[i], &name, &offset);
9646283Sdfr		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
9798944Sobrien		    name, offset);
9819370Spst	}
9998944Sobrien}
10046283Sdfr
10119370Spstvoid
10219370Spststack_sbuf_print(struct sbuf *sb, struct stack *st)
10398944Sobrien{
10419370Spst	const char *name;
10519370Spst	long offset;
10619370Spst	int i;
10719370Spst
10898944Sobrien	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
10998944Sobrien	for (i = 0; i < st->depth; i++) {
11098944Sobrien		stack_symbol(st->pcs[i], &name, &offset);
11119370Spst		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
11219370Spst		    name, offset);
11319370Spst	}
11498944Sobrien}
11598944Sobrien
11698944Sobrien#ifdef KTR
11719370Spstvoid
11819370Spststack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth,
11919370Spst    int cheap)
12019370Spst{
12198944Sobrien	const char *name;
12298944Sobrien	long offset;
12398944Sobrien	int i;
12419370Spst
12519370Spst	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
12646283Sdfr	if (cheap) {
12746283Sdfr		ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p",
12846283Sdfr		    st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3],
12946283Sdfr		    st->pcs[4], st->pcs[5]);
13019370Spst		if (st->depth <= 6)
13119370Spst			return;
13298944Sobrien		ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p",
13319370Spst		    st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9],
13419370Spst		    st->pcs[10], st->pcs[11]);
13519370Spst		if (st->depth <= 12)
13619370Spst			return;
13719370Spst		ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p",
13819370Spst		    st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15],
13919370Spst		    st->pcs[16], st->pcs[17]);
14019370Spst	} else {
14198944Sobrien		if (depth == 0 || st->depth < depth)
14298944Sobrien			depth = st->depth;
14398944Sobrien		for (i = 0; i < depth; i++) {
14419370Spst			stack_symbol(st->pcs[i], &name, &offset);
14519370Spst			ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx",
14619370Spst			    i, st->pcs[i], (u_long)name, offset, 0, 0);
14719370Spst		}
14819370Spst	}
14919370Spst}
15019370Spst#endif
15119370Spst
152130803Smarcelstatic void
15346283Sdfrstack_symbol(vm_offset_t pc, const char **name, long *offset)
15498944Sobrien{
15598944Sobrien	linker_symval_t symval;
156130803Smarcel	c_linker_sym_t sym;
15798944Sobrien
15846283Sdfr	if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0)
159130803Smarcel		goto out;
160130803Smarcel	if (linker_ddb_symbol_values(sym, &symval) != 0)
161130803Smarcel		goto out;
16246283Sdfr	if (symval.name != NULL) {
16398944Sobrien		*name = symval.name;
16446283Sdfr		return;
16546283Sdfr	}
16646283Sdfrout:
167130803Smarcel	*offset = 0;
168130803Smarcel	*name = "Unknown func";
169130803Smarcel}
170130803Smarcel