xref: /freebsd/sys/kern/subr_stack.c (revision 60d717baf2144cf344ec9b47d715ce837b5d46d4)
1  /*-
2   * SPDX-License-Identifier: BSD-2-Clause
3   *
4   * Copyright (c) 2005 Antoine Brodin
5   * All rights reserved.
6   *
7   * Redistribution and use in source and binary forms, with or without
8   * modification, are permitted provided that the following conditions
9   * are met:
10   * 1. Redistributions of source code must retain the above copyright
11   *    notice, this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in the
14   *    documentation and/or other materials provided with the distribution.
15   *
16   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26   * SUCH DAMAGE.
27   */
28  
29  #include "opt_ddb.h"
30  
31  #include <sys/param.h>
32  #include <sys/kernel.h>
33  #ifdef KTR
34  #include <sys/ktr.h>
35  #endif
36  #include <sys/linker.h>
37  #include <sys/malloc.h>
38  #include <sys/sbuf.h>
39  #include <sys/stack.h>
40  #include <sys/systm.h>
41  #include <sys/sysctl.h>
42  
43  FEATURE(stack, "Support for capturing kernel stack");
44  
45  MALLOC_DEFINE(M_STACK, "stack", "Stack Traces");
46  
47  static int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen,
48  	    long *offset, int flags);
49  static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset);
50  
51  struct stack *
52  stack_create(int flags)
53  {
54  	struct stack *st;
55  
56  	st = malloc(sizeof(*st), M_STACK, flags | M_ZERO);
57  	return (st);
58  }
59  
60  void
61  stack_destroy(struct stack *st)
62  {
63  
64  	free(st, M_STACK);
65  }
66  
67  int
68  stack_put(struct stack *st, vm_offset_t pc)
69  {
70  
71  	if (st->depth < STACK_MAX) {
72  		st->pcs[st->depth++] = pc;
73  		return (0);
74  	} else
75  		return (-1);
76  }
77  
78  void
79  stack_copy(const struct stack *src, struct stack *dst)
80  {
81  
82  	*dst = *src;
83  }
84  
85  void
86  stack_zero(struct stack *st)
87  {
88  
89  	bzero(st, sizeof *st);
90  }
91  
92  void
93  stack_print(const struct stack *st)
94  {
95  	char namebuf[64];
96  	long offset;
97  	int i;
98  
99  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
100  	for (i = 0; i < st->depth; i++) {
101  		(void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
102  		    &offset, M_WAITOK);
103  		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
104  		    namebuf, offset);
105  	}
106  }
107  
108  void
109  stack_print_short(const struct stack *st)
110  {
111  	char namebuf[64];
112  	long offset;
113  	int i;
114  
115  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
116  	for (i = 0; i < st->depth; i++) {
117  		if (i > 0)
118  			printf(" ");
119  		if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
120  		    &offset, M_WAITOK) == 0)
121  			printf("%s+%#lx", namebuf, offset);
122  		else
123  			printf("%p", (void *)st->pcs[i]);
124  	}
125  	printf("\n");
126  }
127  
128  void
129  stack_print_ddb(const struct stack *st)
130  {
131  	const char *name;
132  	long offset;
133  	int i;
134  
135  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
136  	for (i = 0; i < st->depth; i++) {
137  		stack_symbol_ddb(st->pcs[i], &name, &offset);
138  		printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
139  		    name, offset);
140  	}
141  }
142  
143  #if defined(DDB) || defined(WITNESS)
144  void
145  stack_print_short_ddb(const struct stack *st)
146  {
147  	const char *name;
148  	long offset;
149  	int i;
150  
151  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
152  	for (i = 0; i < st->depth; i++) {
153  		if (i > 0)
154  			printf(" ");
155  		if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0)
156  			printf("%s+%#lx", name, offset);
157  		else
158  			printf("%p", (void *)st->pcs[i]);
159  	}
160  	printf("\n");
161  }
162  #endif
163  
164  /*
165   * Format stack into sbuf from live kernel.
166   *
167   * flags - M_WAITOK or M_NOWAIT (EWOULDBLOCK).
168   */
169  int
170  stack_sbuf_print_flags(struct sbuf *sb, const struct stack *st, int flags,
171      enum stack_sbuf_fmt format)
172  {
173  	char namebuf[64];
174  	long offset;
175  	int i, error;
176  
177  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
178  	for (i = 0; i < st->depth; i++) {
179  		error = stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
180  		    &offset, flags);
181  		if (error == EWOULDBLOCK)
182  			return (error);
183  		switch (format) {
184  		case STACK_SBUF_FMT_LONG:
185  			sbuf_printf(sb, "#%d %p at %s+%#lx\n", i,
186  			    (void *)st->pcs[i], namebuf, offset);
187  			break;
188  		case STACK_SBUF_FMT_COMPACT:
189  			sbuf_printf(sb, "%s+%#lx ", namebuf, offset);
190  			break;
191  		default:
192  			__assert_unreachable();
193  		}
194  	}
195  	sbuf_nl_terminate(sb);
196  	return (0);
197  }
198  
199  void
200  stack_sbuf_print(struct sbuf *sb, const struct stack *st)
201  {
202  
203  	(void)stack_sbuf_print_flags(sb, st, M_WAITOK, STACK_SBUF_FMT_LONG);
204  }
205  
206  #if defined(DDB) || defined(WITNESS)
207  void
208  stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st)
209  {
210  	const char *name;
211  	long offset;
212  	int i;
213  
214  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
215  	for (i = 0; i < st->depth; i++) {
216  		(void)stack_symbol_ddb(st->pcs[i], &name, &offset);
217  		sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
218  		    name, offset);
219  	}
220  }
221  #endif
222  
223  #ifdef KTR
224  void
225  stack_ktr(u_int mask, const char *file, int line, const struct stack *st,
226      u_int depth)
227  {
228  #ifdef DDB
229  	const char *name;
230  	long offset;
231  	int i;
232  #endif
233  
234  	KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
235  #ifdef DDB
236  	if (depth == 0 || st->depth < depth)
237  		depth = st->depth;
238  	for (i = 0; i < depth; i++) {
239  		(void)stack_symbol_ddb(st->pcs[i], &name, &offset);
240  		ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx",
241  		    i, st->pcs[i], (u_long)name, offset, 0, 0);
242  	}
243  #endif
244  }
245  #endif
246  
247  /*
248   * Two variants of stack symbol lookup -- one that uses the DDB interfaces
249   * and bypasses linker locking, and the other that doesn't.
250   */
251  static int
252  stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset,
253      int flags)
254  {
255  	int error;
256  
257  	error = linker_search_symbol_name_flags((caddr_t)pc, namebuf, buflen,
258  	    offset, flags);
259  	if (error == 0 || error == EWOULDBLOCK)
260  		return (error);
261  
262  	*offset = 0;
263  	strlcpy(namebuf, "??", buflen);
264  	return (ENOENT);
265  }
266  
267  static int
268  stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset)
269  {
270  	linker_symval_t symval;
271  	c_linker_sym_t sym;
272  
273  	if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0)
274  		goto out;
275  	if (linker_ddb_symbol_values(sym, &symval) != 0)
276  		goto out;
277  	if (symval.name != NULL) {
278  		*name = symval.name;
279  		return (0);
280  	}
281   out:
282  	*offset = 0;
283  	*name = "??";
284  	return (ENOENT);
285  }
286