subr_stack.c revision 212994
1148666Sjeff/*-
2148666Sjeff * Copyright (c) 2005 Antoine Brodin
3148666Sjeff * All rights reserved.
4148666Sjeff *
5148666Sjeff * Redistribution and use in source and binary forms, with or without
6148666Sjeff * modification, are permitted provided that the following conditions
7148666Sjeff * are met:
8148666Sjeff * 1. Redistributions of source code must retain the above copyright
9148666Sjeff *    notice, this list of conditions and the following disclaimer.
10148666Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11148666Sjeff *    notice, this list of conditions and the following disclaimer in the
12148666Sjeff *    documentation and/or other materials provided with the distribution.
13148666Sjeff *
14148666Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15148666Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148666Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148666Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18148666Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148666Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148666Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148666Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148666Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148666Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148666Sjeff * SUCH DAMAGE.
25148666Sjeff */
26148666Sjeff
27174137Srwatson#include "opt_ddb.h"
28174137Srwatson
29148666Sjeff#include <sys/cdefs.h>
30148666Sjeff__FBSDID("$FreeBSD: head/sys/kern/subr_stack.c 212994 2010-09-22 06:45:07Z avg $");
31148666Sjeff
32148666Sjeff#include <sys/param.h>
33148666Sjeff#include <sys/kernel.h>
34148666Sjeff#ifdef KTR
35148666Sjeff#include <sys/ktr.h>
36148666Sjeff#endif
37148666Sjeff#include <sys/linker.h>
38148666Sjeff#include <sys/malloc.h>
39148666Sjeff#include <sys/sbuf.h>
40148666Sjeff#include <sys/stack.h>
41148666Sjeff#include <sys/systm.h>
42148666Sjeff
43180495Santoinestatic MALLOC_DEFINE(M_STACK, "stack", "Stack Traces");
44148666Sjeff
45194828Srwatsonstatic int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen,
46174137Srwatson	    long *offset);
47194828Srwatsonstatic int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset);
48148666Sjeff
49148666Sjeffstruct stack *
50148666Sjeffstack_create(void)
51148666Sjeff{
52148666Sjeff	struct stack *st;
53148666Sjeff
54148666Sjeff	st = malloc(sizeof *st, M_STACK, M_WAITOK | M_ZERO);
55148666Sjeff	return (st);
56148666Sjeff}
57148666Sjeff
58148666Sjeffvoid
59148666Sjeffstack_destroy(struct stack *st)
60148666Sjeff{
61148666Sjeff
62148666Sjeff	free(st, M_STACK);
63148666Sjeff}
64148666Sjeff
65148666Sjeffint
66148666Sjeffstack_put(struct stack *st, vm_offset_t pc)
67148666Sjeff{
68148666Sjeff
69148666Sjeff	if (st->depth < STACK_MAX) {
70148666Sjeff		st->pcs[st->depth++] = pc;
71148666Sjeff		return (0);
72148666Sjeff	} else
73148666Sjeff		return (-1);
74148666Sjeff}
75148666Sjeff
76148666Sjeffvoid
77148666Sjeffstack_copy(struct stack *src, struct stack *dst)
78148666Sjeff{
79148666Sjeff
80148666Sjeff	*dst = *src;
81148666Sjeff}
82148666Sjeff
83148666Sjeffvoid
84148666Sjeffstack_zero(struct stack *st)
85148666Sjeff{
86148666Sjeff
87148666Sjeff	bzero(st, sizeof *st);
88148666Sjeff}
89148666Sjeff
90148666Sjeffvoid
91148666Sjeffstack_print(struct stack *st)
92148666Sjeff{
93174137Srwatson	char namebuf[64];
94148666Sjeff	long offset;
95148666Sjeff	int i;
96148666Sjeff
97159022Skris	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
98148666Sjeff	for (i = 0; i < st->depth; i++) {
99194828Srwatson		(void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
100194828Srwatson		    &offset);
101148666Sjeff		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
102174137Srwatson		    namebuf, offset);
103148666Sjeff	}
104148666Sjeff}
105148666Sjeff
106194828Srwatsonvoid
107194828Srwatsonstack_print_short(struct stack *st)
108194828Srwatson{
109194828Srwatson	char namebuf[64];
110194828Srwatson	long offset;
111194828Srwatson	int i;
112194828Srwatson
113194828Srwatson	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
114194828Srwatson	for (i = 0; i < st->depth; i++) {
115194828Srwatson		if (i > 0)
116194828Srwatson			printf(" ");
117194828Srwatson		if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
118194828Srwatson		    &offset) == 0)
119194828Srwatson			printf("%s+%#lx", namebuf, offset);
120194828Srwatson		else
121194828Srwatson			printf("%p", (void *)st->pcs[i]);
122194828Srwatson	}
123194828Srwatson	printf("\n");
124194828Srwatson}
125194828Srwatson
126148666Sjeffvoid
127174137Srwatsonstack_print_ddb(struct stack *st)
128174137Srwatson{
129184060Skib	const char *name;
130174137Srwatson	long offset;
131174137Srwatson	int i;
132174137Srwatson
133174137Srwatson	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
134174137Srwatson	for (i = 0; i < st->depth; i++) {
135184060Skib		stack_symbol_ddb(st->pcs[i], &name, &offset);
136174137Srwatson		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
137184060Skib		    name, offset);
138174137Srwatson	}
139174137Srwatson}
140194828Srwatson
141212994Savg#ifdef DDB
142194828Srwatsonvoid
143194828Srwatsonstack_print_short_ddb(struct stack *st)
144194828Srwatson{
145194828Srwatson	const char *name;
146194828Srwatson	long offset;
147194828Srwatson	int i;
148194828Srwatson
149194828Srwatson	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
150194828Srwatson	for (i = 0; i < st->depth; i++) {
151194828Srwatson		if (i > 0)
152194828Srwatson			printf(" ");
153194828Srwatson		if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0)
154194828Srwatson			printf("%s+%#lx", name, offset);
155194828Srwatson		else
156194828Srwatson			printf("%p", (void *)st->pcs[i]);
157194828Srwatson	}
158194828Srwatson	printf("\n");
159194828Srwatson}
160174195Srwatson#endif
161174137Srwatson
162174137Srwatson/*
163174137Srwatson * Two print routines -- one for use from DDB and DDB-like contexts, the
164174137Srwatson * other for use in the live kernel.
165174137Srwatson */
166174137Srwatsonvoid
167148666Sjeffstack_sbuf_print(struct sbuf *sb, struct stack *st)
168148666Sjeff{
169174137Srwatson	char namebuf[64];
170148666Sjeff	long offset;
171148666Sjeff	int i;
172148666Sjeff
173159022Skris	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
174148666Sjeff	for (i = 0; i < st->depth; i++) {
175194828Srwatson		(void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
176194828Srwatson		    &offset);
177148666Sjeff		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
178174137Srwatson		    namebuf, offset);
179148666Sjeff	}
180148666Sjeff}
181148666Sjeff
182174137Srwatson#ifdef DDB
183174137Srwatsonvoid
184174137Srwatsonstack_sbuf_print_ddb(struct sbuf *sb, struct stack *st)
185174137Srwatson{
186184060Skib	const char *name;
187174137Srwatson	long offset;
188174137Srwatson	int i;
189174137Srwatson
190174137Srwatson	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
191174137Srwatson	for (i = 0; i < st->depth; i++) {
192194828Srwatson		(void)stack_symbol_ddb(st->pcs[i], &name, &offset);
193174137Srwatson		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
194184060Skib		    name, offset);
195174137Srwatson	}
196174137Srwatson}
197184487Ssobomax#endif
198174137Srwatson
199148666Sjeff#ifdef KTR
200148666Sjeffvoid
201149574Spjdstack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth,
202149574Spjd    int cheap)
203148666Sjeff{
204184487Ssobomax#ifdef DDB
205184060Skib	const char *name;
206148666Sjeff	long offset;
207148666Sjeff	int i;
208184487Ssobomax#endif
209148666Sjeff
210159022Skris	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
211148666Sjeff	if (cheap) {
212148666Sjeff		ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p",
213148666Sjeff		    st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3],
214148666Sjeff		    st->pcs[4], st->pcs[5]);
215148666Sjeff		if (st->depth <= 6)
216148666Sjeff			return;
217148666Sjeff		ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p",
218148666Sjeff		    st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9],
219148666Sjeff		    st->pcs[10], st->pcs[11]);
220148666Sjeff		if (st->depth <= 12)
221148666Sjeff			return;
222148666Sjeff		ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p",
223148666Sjeff		    st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15],
224148666Sjeff		    st->pcs[16], st->pcs[17]);
225184487Ssobomax#ifdef DDB
226149574Spjd	} else {
227149574Spjd		if (depth == 0 || st->depth < depth)
228149574Spjd			depth = st->depth;
229149574Spjd		for (i = 0; i < depth; i++) {
230194828Srwatson			(void)stack_symbol_ddb(st->pcs[i], &name, &offset);
231148666Sjeff			ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx",
232184060Skib			    i, st->pcs[i], (u_long)name, offset, 0, 0);
233148666Sjeff		}
234184487Ssobomax#endif
235149574Spjd	}
236148666Sjeff}
237148666Sjeff#endif
238148666Sjeff
239174137Srwatson/*
240174137Srwatson * Two variants of stack symbol lookup -- one that uses the DDB interfaces
241174137Srwatson * and bypasses linker locking, and the other that doesn't.
242174137Srwatson */
243194828Srwatsonstatic int
244174137Srwatsonstack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset)
245148666Sjeff{
246148666Sjeff
247174137Srwatson	if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen,
248174137Srwatson	    offset) != 0) {
249174137Srwatson		*offset = 0;
250174222Srwatson		strlcpy(namebuf, "??", buflen);
251194828Srwatson		return (ENOENT);
252194828Srwatson	} else
253194828Srwatson		return (0);
254148666Sjeff}
255174137Srwatson
256194828Srwatsonstatic int
257184060Skibstack_symbol_ddb(vm_offset_t pc, const char **name, long *offset)
258174137Srwatson{
259184060Skib	linker_symval_t symval;
260184060Skib	c_linker_sym_t sym;
261174137Srwatson
262184060Skib	if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0)
263184060Skib		goto out;
264184060Skib	if (linker_ddb_symbol_values(sym, &symval) != 0)
265184060Skib		goto out;
266184060Skib	if (symval.name != NULL) {
267184060Skib		*name = symval.name;
268194828Srwatson		return (0);
269184060Skib	}
270184060Skib out:
271184060Skib	*offset = 0;
272184060Skib	*name = "??";
273194828Srwatson	return (ENOENT);
274174137Srwatson}
275