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/ddb/db_sym.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 /*      $NetBSD: db_sym.c,v 1.71 2022/08/30 22:38:01 riastradh Exp $    */
    2 
    3 /*
    4  * Mach Operating System
    5  * Copyright (c) 1991,1990 Carnegie Mellon University
    6  * All Rights Reserved.
    7  *
    8  * Permission to use, copy, modify and distribute this software and its
    9  * documentation is hereby granted, provided that both the copyright
   10  * notice and this permission notice appear in all copies of the
   11  * software, derivative works or modified versions, and any portions
   12  * thereof, and that both notices appear in supporting documentation.
   13  *
   14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   17  *
   18  * Carnegie Mellon requests users of this software to return to
   19  *
   20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   21  *  School of Computer Science
   22  *  Carnegie Mellon University
   23  *  Pittsburgh PA 15213-3890
   24  *
   25  * any improvements or extensions that they make and grant Carnegie the
   26  * rights to redistribute these changes.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.71 2022/08/30 22:38:01 riastradh Exp $");
   31 
   32 #ifdef _KERNEL_OPT
   33 #include "opt_ddbparam.h"
   34 #endif
   35 
   36 #include <sys/param.h>
   37 #include <sys/proc.h>
   38 #include <sys/systm.h>
   39 #include <sys/ksyms.h>
   40 #include <sys/pserialize.h>
   41 
   42 #include <ddb/ddb.h>
   43 
   44 static void             db_symsplit(char *, char **, char **);
   45 
   46 
   47 #ifndef _KERNEL
   48 #define TBLNAME "netbsd"
   49 
   50 #define use_ksyms 0
   51 
   52 const db_symformat_t *db_symformat;
   53 static db_forall_func_t db_sift;
   54 extern db_symformat_t db_symformat_elf;
   55 #endif
   56 
   57 
   58 /*
   59  * Initialize the kernel debugger by initializing the master symbol
   60  * table.  Note that if initializing the master symbol table fails,
   61  * no other symbol tables can be loaded.
   62  */
   63 void
   64 ddb_init(int symsize, void *vss, void *vse)
   65 {
   66 #ifdef _KERNEL
   67         ksyms_addsyms_elf(symsize, vss, vse);   /* Will complain if necessary */
   68 #else   /* _KERNEL */
   69         db_symformat = &db_symformat_elf;
   70         if ((*db_symformat->sym_init)(symsize, vss, vse, TBLNAME) != true)
   71                 printf("sym_init failed");
   72 #endif  /* _KERNEL */
   73 }
   74 
   75 bool
   76 db_eqname(const char *src, const char *dst, int c)
   77 {
   78 
   79         if (!strcmp(src, dst))
   80                 return (true);
   81         if (src[0] == c)
   82                 return (!strcmp(src+1,dst));
   83         return (false);
   84 }
   85 
   86 bool
   87 db_value_of_name(const char *name, db_expr_t *valuep)
   88 {
   89         char symbol[128];
   90         char *mod, *sym;
   91 #ifdef _KERNEL
   92         unsigned long uval;
   93         long val;
   94 #endif
   95 
   96 #ifndef _KERNEL
   97         if (!use_ksyms) {
   98                 db_sym_t ssym;
   99 
  100                 /*
  101                  * Cannot load symtabs in a.out kernels, so the ':'
  102                  * style of selecting modules is irrelevant.
  103                  */
  104                 ssym = (*db_symformat->sym_lookup)(NULL, name);
  105                 if (ssym == DB_SYM_NULL)
  106                         return (false);
  107                 db_symbol_values(ssym, &name, valuep);
  108                 return (true);
  109         }
  110 #endif
  111 
  112         (void)strlcpy(symbol, name, sizeof(symbol));
  113         db_symsplit(symbol, &mod, &sym);
  114 #ifdef _KERNEL
  115         if (ksyms_getval_unlocked(mod, sym, NULL, &uval, KSYMS_EXTERN) == 0) {
  116                 val = (long) uval;
  117                 *valuep = (db_expr_t)val;
  118                 return true;
  119         }
  120         if (ksyms_getval_unlocked(mod, sym, NULL, &uval, KSYMS_ANY) == 0) {
  121                 val = (long) uval;
  122                 *valuep = (db_expr_t)val;
  123                 return true;
  124         }
  125 #endif
  126         return false;
  127 }
  128 
  129 #ifndef _KERNEL
  130 /* Private structure for passing args to db_sift() from db_sifting(). */
  131 struct db_sift_args {
  132         char    *symstr;
  133         int     mode;
  134 };
  135 
  136 /*
  137  * Does the work of db_sifting(), called once for each
  138  * symbol via db_forall(), prints out symbols matching
  139  * criteria.
  140  */
  141 static void
  142 db_sift(db_symtab_t *stab, db_sym_t sym, char *name,
  143     char *suffix, int prefix, void *arg)
  144 {
  145         char c, sc;
  146         char *find, *p;
  147         size_t len;
  148         struct db_sift_args *dsa;
  149 
  150         dsa = (struct db_sift_args*)arg;
  151 
  152         find = dsa->symstr;     /* String we're looking for. */
  153         p = name;               /* String we're searching within. */
  154 
  155         /* Matching algorithm cribbed from strstr(), which is not
  156            in the kernel. */
  157         if ((c = *find++) != 0) {
  158                 len = strlen(find);
  159                 do {
  160                         do {
  161                                 if ((sc = *p++) == 0)
  162                                         return;
  163                         } while (sc != c);
  164                 } while (strncmp(p, find, len) != 0);
  165         }
  166         if (dsa->mode=='F')     /* ala ls -F */
  167                 db_printf("%s%s ", name, suffix);
  168         else
  169                 db_printf("%s ", name);
  170 }
  171 #endif
  172 
  173 /*
  174  * "Sift" for a partial symbol.
  175  * Named for the Sun OpenPROM command ("sifting").
  176  * If the symbol has a qualifier (e.g., ux:vm_map),
  177  * then only the specified symbol table will be searched;
  178  * otherwise, all symbol tables will be searched..
  179  *
  180  * "mode" is how-to-display, set from modifiers.
  181  */
  182 void
  183 db_sifting(char *symstr, int mode)
  184 {
  185 #ifdef _KERNEL
  186         char *mod, *sym;
  187 #endif
  188 
  189 #ifndef _KERNEL
  190         struct db_sift_args dsa;
  191 
  192         if (!use_ksyms) {
  193                 dsa.symstr = symstr;
  194                 dsa.mode = mode;
  195                 (*db_symformat->sym_forall)(NULL, db_sift, &dsa);
  196                 db_printf("\n");
  197                 return;
  198         }
  199 #endif
  200 
  201 #ifdef _KERNEL
  202         db_symsplit(symstr, &mod, &sym);
  203         if (ksyms_sift(mod, sym, mode) == ENODEV)
  204                 db_error("invalid symbol table name");
  205 #endif
  206 }
  207 
  208 /*
  209  * Find the closest symbol to val, and return its name
  210  * and the difference between val and the symbol found.
  211  */
  212 db_sym_t
  213 db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
  214 {
  215         unsigned int diff;
  216         db_sym_t ret = DB_SYM_NULL;
  217 #ifdef _KERNEL
  218         unsigned long naddr;
  219         const char *mod;
  220         const char *sym;
  221 #endif
  222 
  223 #ifndef _KERNEL
  224         if (!use_ksyms) {
  225                 db_expr_t newdiff;
  226                 db_sym_t ssym;
  227 
  228                 diff = ~0u;
  229                 newdiff = ~0;
  230                 ssym = (*db_symformat->sym_search)
  231                     (NULL, val, strategy, &newdiff);
  232                 if ((unsigned int) newdiff < diff) {
  233                         diff = newdiff;
  234                         ret = ssym;
  235                 }
  236                 *offp = diff;
  237                 return ret;
  238         }
  239 #endif
  240 
  241 #ifdef _KERNEL
  242         if (ksyms_getname(&mod, &sym, (vaddr_t)val, strategy) == 0) {
  243                 (void)ksyms_getval_unlocked(mod, sym, NULL, &naddr, KSYMS_ANY);
  244                 diff = val - (db_addr_t)naddr;
  245                 ret = (db_sym_t)naddr;
  246         } else
  247 #endif
  248                 diff = 0;
  249         *offp = diff;
  250         return ret;
  251 }
  252 
  253 /*
  254  * Return name and value of a symbol
  255  */
  256 void
  257 db_symbol_values(db_sym_t sym, const char **namep, db_expr_t *valuep)
  258 {
  259 #ifdef _KERNEL
  260         const char *mod;
  261 #endif
  262 
  263         if (sym == DB_SYM_NULL) {
  264                 *namep = 0;
  265                 return;
  266         }
  267 
  268 #ifndef _KERNEL
  269         if (!use_ksyms) {
  270                 db_expr_t value;
  271 
  272                 (*db_symformat->sym_value)(NULL, sym, namep, &value);
  273                 if (valuep)
  274                         *valuep = value;
  275                 return;
  276         }
  277 #endif
  278 
  279 #ifdef _KERNEL
  280         if (ksyms_getname(&mod, namep, (vaddr_t)sym,
  281             KSYMS_ANY|KSYMS_EXACT) == 0) {
  282                 if (valuep)
  283                         *valuep = sym;
  284         } else
  285 #endif
  286                 *namep = NULL;
  287 }
  288 
  289 
  290 /*
  291  * Print a the closest symbol to value
  292  *
  293  * After matching the symbol according to the given strategy
  294  * we print it in the name+offset format, provided the symbol's
  295  * value is close enough (eg smaller than db_maxoff).
  296  * We also attempt to print [filename:linenum] when applicable
  297  * (eg for procedure names).
  298  *
  299  * If we could not find a reasonable name+offset representation,
  300  * then we just print the value in hex.  Small values might get
  301  * bogus symbol associations, e.g. 3 might get some absolute
  302  * value like _INCLUDE_VERSION or something, therefore we do
  303  * not accept symbols whose value is zero (and use plain hex).
  304  */
  305 unsigned int    db_maxoff = 0x100000;
  306 
  307 void
  308 db_symstr(char *buf, size_t buflen, db_expr_t off, db_strategy_t strategy)
  309 {
  310         const char  *name;
  311 #ifdef _KERNEL
  312         const char *mod;
  313         unsigned long val;
  314 #endif
  315 
  316 #ifndef _KERNEL
  317         if (!use_ksyms) {
  318                 db_expr_t       d;
  319                 char            *filename;
  320                 db_expr_t       value;
  321                 int             linenum;
  322                 db_sym_t        cursym;
  323 
  324                 cursym = db_search_symbol(off, strategy, &d);
  325                 db_symbol_values(cursym, &name, &value);
  326                 if (name != NULL && ((unsigned int)d < db_maxoff) &&
  327                     value != 0) {
  328                         strlcpy(buf, name, buflen);
  329                         if (d) {
  330                                 strlcat(buf, "+", buflen);
  331                                 db_format_radix(buf + strlen(buf), 24, d, true);
  332                         }
  333                         if (strategy == DB_STGY_PROC) {
  334                                 if ((*db_symformat->sym_line_at_pc)
  335                                     (NULL, cursym, &filename, &linenum, off)) {
  336                                         size_t len = strlen(buf);
  337                                         snprintf(buf + len, buflen - len,
  338                                             " [%s:%d]", filename, linenum);
  339                                 }
  340                         }
  341                         return;
  342                 }
  343                 strlcpy(buf, db_num_to_str(off), buflen);
  344                 return;
  345         }
  346 #endif
  347 #ifdef _KERNEL
  348         const int s = pserialize_read_enter();
  349         if (ksyms_getname(&mod, &name, (vaddr_t)off,
  350             strategy|KSYMS_CLOSEST) == 0) {
  351                 (void)ksyms_getval_unlocked(mod, name, NULL, &val, KSYMS_ANY);
  352                 if (strategy & KSYMS_PROC && val == off) {
  353                         if (ksyms_getname(&mod, &name, (vaddr_t)off - 1,
  354                                           strategy|KSYMS_CLOSEST) != 0)
  355                                 goto hex_fallback;
  356                         (void)ksyms_getval_unlocked(mod, name, NULL, &val, KSYMS_ANY);
  357                 }
  358                 if (((off - val) < db_maxoff) && val) {
  359                         snprintf(buf, buflen, "%s:%s", mod, name);
  360                         if (off - val) {
  361                                 strlcat(buf, "+", buflen);
  362                                 db_format_radix(buf+strlen(buf),
  363                                     24, off - val, true);
  364                         }
  365 #ifdef notyet
  366                         if (strategy & KSYMS_PROC) {
  367                                 if (ksyms_fmaddr(off, &filename, &linenum) == 0)
  368                                         snprintf(buf + strlen(buf),
  369                                             buflen - strlen(buf),
  370                                             " [%s:%d]", filename, linenum);
  371                         }
  372 #endif
  373                         goto out;
  374                 }
  375         }
  376 hex_fallback:
  377         db_num_to_strbuf(off, buf, buflen);
  378 out:    pserialize_read_exit(s);
  379 #endif
  380 }
  381 
  382 void
  383 db_printsym(db_expr_t off, db_strategy_t strategy,
  384     void (*pr)(const char *, ...))
  385 {
  386         const char  *name;
  387 #ifdef _KERNEL
  388         const char *mod;
  389         unsigned long uval;
  390         long val;
  391 #endif
  392 #ifdef notyet
  393         char *filename;
  394         int  linenum;
  395 #endif
  396 
  397 #ifndef _KERNEL
  398         if (!use_ksyms) {
  399                 db_expr_t       d;
  400                 char            *filename;
  401                 db_expr_t       value;
  402                 int             linenum;
  403                 db_sym_t        cursym;
  404 
  405                 cursym = db_search_symbol(off, strategy, &d);
  406                 db_symbol_values(cursym, &name, &value);
  407                 if (name != NULL && ((unsigned int)d < db_maxoff) &&
  408                     value != 0) {
  409                         (*pr)("%s", name);
  410                         if (d) {
  411                                 char tbuf[24];
  412 
  413                                 db_format_radix(tbuf, 24, d, true);
  414                                 (*pr)("+%s", tbuf);
  415                         }
  416                         if (strategy == DB_STGY_PROC) {
  417                                 if ((*db_symformat->sym_line_at_pc)
  418                                     (NULL, cursym, &filename, &linenum, off))
  419                                         (*pr)(" [%s:%d]", filename, linenum);
  420                         }
  421                         return;
  422                 }
  423                 (*pr)("%s", db_num_to_str(off));
  424                 return;
  425         }
  426 #endif
  427 #ifdef _KERNEL
  428         if (ksyms_getname(&mod, &name, (vaddr_t)off,
  429             strategy|KSYMS_CLOSEST) == 0) {
  430                 (void)ksyms_getval_unlocked(mod, name, NULL, &uval, KSYMS_ANY);
  431                 if (strategy & KSYMS_PROC && uval == off) {
  432                         if (ksyms_getname(&mod, &name, (vaddr_t)off - 1,
  433                                           strategy|KSYMS_CLOSEST) != 0)
  434                                 goto out;
  435                         (void)ksyms_getval_unlocked(mod, name, NULL, &uval, KSYMS_ANY);
  436                 }
  437                 val = (long) uval;
  438                 if (((off - val) < db_maxoff) && val) {
  439                         (*pr)("%s:%s", mod, name);
  440                         if (off - val) {
  441                                 char tbuf[24];
  442 
  443                                 db_format_radix(tbuf, 24, off - val, true);
  444                                 (*pr)("+%s", tbuf);
  445                         }
  446 #ifdef notyet
  447                         if (strategy & KSYMS_PROC) {
  448                                 if (ksyms_fmaddr(off, &filename, &linenum) == 0)
  449                                         (*pr)(" [%s:%d]", filename, linenum);
  450                         }
  451 #endif
  452                         return;
  453                 }
  454         }
  455  out:;
  456 #endif
  457         (*pr)("%s", db_num_to_str(off));
  458         return;
  459 }
  460 
  461 /*
  462  * Splits a string in the form "mod:sym" to two strings.
  463  */
  464 static void
  465 db_symsplit(char *str, char **mod, char **sym)
  466 {
  467         char *cp;
  468 
  469         if ((cp = strchr(str, ':')) != NULL) {
  470                 *cp++ = '\0';
  471                 *mod = str;
  472                 *sym = cp;
  473         } else {
  474                 *mod = NULL;
  475                 *sym = str;
  476         }
  477 }
  478 
  479 bool
  480 db_sym_numargs(db_sym_t cursym, int *nargp, char **argnamep)
  481 {
  482 #ifndef _KERNEL
  483         if (!use_ksyms)
  484                 return ((*db_symformat->sym_numargs)(NULL, cursym, nargp,
  485                     argnamep));
  486 #endif
  487         return (false);
  488 }
  489 

Cache object: 0437d9f82f0621957f519e912e0d0d3c


[ 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.