The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_stack.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    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/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/kernel.h>
   36 #ifdef KTR
   37 #include <sys/ktr.h>
   38 #endif
   39 #include <sys/linker.h>
   40 #include <sys/malloc.h>
   41 #include <sys/sbuf.h>
   42 #include <sys/stack.h>
   43 #include <sys/systm.h>
   44 #include <sys/sysctl.h>
   45 
   46 FEATURE(stack, "Support for capturing kernel stack");
   47 
   48 MALLOC_DEFINE(M_STACK, "stack", "Stack Traces");
   49 
   50 static int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen,
   51             long *offset, int flags);
   52 static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset);
   53 
   54 struct stack *
   55 stack_create(int flags)
   56 {
   57         struct stack *st;
   58 
   59         st = malloc(sizeof(*st), M_STACK, flags | M_ZERO);
   60         return (st);
   61 }
   62 
   63 void
   64 stack_destroy(struct stack *st)
   65 {
   66 
   67         free(st, M_STACK);
   68 }
   69 
   70 int
   71 stack_put(struct stack *st, vm_offset_t pc)
   72 {
   73 
   74         if (st->depth < STACK_MAX) {
   75                 st->pcs[st->depth++] = pc;
   76                 return (0);
   77         } else
   78                 return (-1);
   79 }
   80 
   81 void
   82 stack_copy(const struct stack *src, struct stack *dst)
   83 {
   84 
   85         *dst = *src;
   86 }
   87 
   88 void
   89 stack_zero(struct stack *st)
   90 {
   91 
   92         bzero(st, sizeof *st);
   93 }
   94 
   95 void
   96 stack_print(const struct stack *st)
   97 {
   98         char namebuf[64];
   99         long offset;
  100         int i;
  101 
  102         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  103         for (i = 0; i < st->depth; i++) {
  104                 (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
  105                     &offset, M_WAITOK);
  106                 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
  107                     namebuf, offset);
  108         }
  109 }
  110 
  111 void
  112 stack_print_short(const struct stack *st)
  113 {
  114         char namebuf[64];
  115         long offset;
  116         int i;
  117 
  118         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  119         for (i = 0; i < st->depth; i++) {
  120                 if (i > 0)
  121                         printf(" ");
  122                 if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
  123                     &offset, M_WAITOK) == 0)
  124                         printf("%s+%#lx", namebuf, offset);
  125                 else
  126                         printf("%p", (void *)st->pcs[i]);
  127         }
  128         printf("\n");
  129 }
  130 
  131 void
  132 stack_print_ddb(const struct stack *st)
  133 {
  134         const char *name;
  135         long offset;
  136         int i;
  137 
  138         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  139         for (i = 0; i < st->depth; i++) {
  140                 stack_symbol_ddb(st->pcs[i], &name, &offset);
  141                 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
  142                     name, offset);
  143         }
  144 }
  145 
  146 #if defined(DDB) || defined(WITNESS)
  147 void
  148 stack_print_short_ddb(const struct stack *st)
  149 {
  150         const char *name;
  151         long offset;
  152         int i;
  153 
  154         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  155         for (i = 0; i < st->depth; i++) {
  156                 if (i > 0)
  157                         printf(" ");
  158                 if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0)
  159                         printf("%s+%#lx", name, offset);
  160                 else
  161                         printf("%p", (void *)st->pcs[i]);
  162         }
  163         printf("\n");
  164 }
  165 #endif
  166 
  167 /*
  168  * Format stack into sbuf from live kernel.
  169  *
  170  * flags - M_WAITOK or M_NOWAIT (EWOULDBLOCK).
  171  */
  172 int
  173 stack_sbuf_print_flags(struct sbuf *sb, const struct stack *st, int flags,
  174     enum stack_sbuf_fmt format)
  175 {
  176         char namebuf[64];
  177         long offset;
  178         int i, error;
  179 
  180         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  181         for (i = 0; i < st->depth; i++) {
  182                 error = stack_symbol(st->pcs[i], namebuf, sizeof(namebuf),
  183                     &offset, flags);
  184                 if (error == EWOULDBLOCK)
  185                         return (error);
  186                 switch (format) {
  187                 case STACK_SBUF_FMT_LONG:
  188                         sbuf_printf(sb, "#%d %p at %s+%#lx\n", i,
  189                             (void *)st->pcs[i], namebuf, offset);
  190                         break;
  191                 case STACK_SBUF_FMT_COMPACT:
  192                         sbuf_printf(sb, "%s+%#lx ", namebuf, offset);
  193                         break;
  194                 default:
  195                         __assert_unreachable();
  196                 }
  197         }
  198         sbuf_nl_terminate(sb);
  199         return (0);
  200 }
  201 
  202 void
  203 stack_sbuf_print(struct sbuf *sb, const struct stack *st)
  204 {
  205 
  206         (void)stack_sbuf_print_flags(sb, st, M_WAITOK, STACK_SBUF_FMT_LONG);
  207 }
  208 
  209 #if defined(DDB) || defined(WITNESS)
  210 void
  211 stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st)
  212 {
  213         const char *name;
  214         long offset;
  215         int i;
  216 
  217         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  218         for (i = 0; i < st->depth; i++) {
  219                 (void)stack_symbol_ddb(st->pcs[i], &name, &offset);
  220                 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i],
  221                     name, offset);
  222         }
  223 }
  224 #endif
  225 
  226 #ifdef KTR
  227 void
  228 stack_ktr(u_int mask, const char *file, int line, const struct stack *st,
  229     u_int depth)
  230 {
  231 #ifdef DDB
  232         const char *name;
  233         long offset;
  234         int i;
  235 #endif
  236 
  237         KASSERT(st->depth <= STACK_MAX, ("bogus stack"));
  238 #ifdef DDB
  239         if (depth == 0 || st->depth < depth)
  240                 depth = st->depth;
  241         for (i = 0; i < depth; i++) {
  242                 (void)stack_symbol_ddb(st->pcs[i], &name, &offset);
  243                 ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx",
  244                     i, st->pcs[i], (u_long)name, offset, 0, 0);
  245         }
  246 #endif
  247 }
  248 #endif
  249 
  250 /*
  251  * Two variants of stack symbol lookup -- one that uses the DDB interfaces
  252  * and bypasses linker locking, and the other that doesn't.
  253  */
  254 static int
  255 stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset,
  256     int flags)
  257 {
  258         int error;
  259 
  260         error = linker_search_symbol_name_flags((caddr_t)pc, namebuf, buflen,
  261             offset, flags);
  262         if (error == 0 || error == EWOULDBLOCK)
  263                 return (error);
  264 
  265         *offset = 0;
  266         strlcpy(namebuf, "??", buflen);
  267         return (ENOENT);
  268 }
  269 
  270 static int
  271 stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset)
  272 {
  273         linker_symval_t symval;
  274         c_linker_sym_t sym;
  275 
  276         if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0)
  277                 goto out;
  278         if (linker_ddb_symbol_values(sym, &symval) != 0)
  279                 goto out;
  280         if (symval.name != NULL) {
  281                 *name = symval.name;
  282                 return (0);
  283         }
  284  out:
  285         *offset = 0;
  286         *name = "??";
  287         return (ENOENT);
  288 }

Cache object: 91d4ce733191aff1e58b2e97f0fd010a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.