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_elf.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 /*      $OpenBSD: db_elf.c,v 1.32 2021/03/12 10:22:46 jsg Exp $ */
    2 /*      $NetBSD: db_elf.c,v 1.13 2000/07/07 21:55:18 jhawk Exp $        */
    3 
    4 /*-
    5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   10  * NASA Ames Research Center.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/stdint.h>
   36 #include <sys/systm.h>
   37 #include <sys/exec.h>
   38 
   39 #include <machine/db_machdep.h>
   40 
   41 #include <ddb/db_elf.h>
   42 #include <ddb/db_sym.h>
   43 #include <ddb/db_output.h>
   44 
   45 #include <sys/exec_elf.h>
   46 
   47 db_symtab_t db_symtab;
   48 
   49 Elf_Sym         *db_elf_sym_lookup(char *);
   50 
   51 /*
   52  * Find the symbol table and strings; tell ddb about them.
   53  *
   54  * symsize:     size of symbol table
   55  * symtab:      pointer to start of symbol table
   56  * esymtab:     pointer to end of string table, for checking - rounded up to
   57  *                  integer boundary
   58  */
   59 int
   60 db_elf_sym_init(int symsize, void *symtab, void *esymtab, const char *name)
   61 {
   62         Elf_Ehdr *elf;
   63         Elf_Shdr *shp;
   64         Elf_Sym *symp, *symtab_start, *symtab_end;
   65         char *shstrtab, *strtab_start, *strtab_end;
   66         int i;
   67         char *errstr = "";
   68 
   69         if (ALIGNED_POINTER(symtab, long) == 0) {
   70                 db_printf("[ %s symbol table has bad start address %p ]\n",
   71                     name, symtab);
   72                 return (0);
   73         }
   74 
   75         symtab_start = symtab_end = NULL;
   76         strtab_start = strtab_end = NULL;
   77 
   78         /*
   79          * The format of the symbols loaded by the boot program is:
   80          *
   81          *      Elf exec header
   82          *      first section header
   83          *      . . .
   84          *      . . .
   85          *      last section header
   86          *      first symbol, string, or line table section
   87          *      . . .
   88          *      . . .
   89          *      last symbol, string, or line table section
   90          */
   91 
   92         /*
   93          * Validate the Elf header.
   94          */
   95         elf = (Elf_Ehdr *)symtab;
   96         if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
   97             elf->e_ident[EI_CLASS] != ELFCLASS) {
   98                 errstr = "bad magic";
   99                 goto badheader;
  100         }
  101 
  102         if (elf->e_machine != ELF_TARG_MACH) {
  103                 errstr = "bad e_machine";
  104                 goto badheader;
  105         }
  106 
  107         /*
  108          * Find the section header string table (.shstrtab), and look up
  109          * the symbol table (.symtab) and string table (.strtab) via their
  110          * names in shstrtab, rather than by table type.
  111          * This works in the presence of multiple string tables, such as
  112          * stabs data found when booting bsd.gdb.
  113          */
  114         shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
  115         shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
  116         for (i = 0; i < elf->e_shnum; i++) {
  117                 if (shp[i].sh_type == SHT_SYMTAB) {
  118                         int j;
  119 
  120                         if (shp[i].sh_offset == 0)
  121                                 continue;
  122                         symtab_start = (Elf_Sym *)((char *)symtab +
  123                             shp[i].sh_offset);
  124                         symtab_end = (Elf_Sym *)((char *)symtab +
  125                             shp[i].sh_offset + shp[i].sh_size);
  126                         j = shp[i].sh_link;
  127                         if (shp[j].sh_offset == 0)
  128                                 continue;
  129                         strtab_start = (char *)symtab + shp[j].sh_offset;
  130                         strtab_end = (char *)symtab + shp[j].sh_offset +
  131                             shp[j].sh_size;
  132                         break;
  133                 }
  134 
  135                 /*
  136                  * This is the old way of doing things.
  137                  * XXX - verify that it's not needed.
  138                  */
  139                 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
  140                         strtab_start = (char *)symtab + shp[i].sh_offset;
  141                         strtab_end = (char *)symtab + shp[i].sh_offset +
  142                             shp[i].sh_size;
  143                 } else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
  144                         symtab_start = (Elf_Sym *)((char *)symtab +
  145                             shp[i].sh_offset);
  146                         symtab_end = (Elf_Sym *)((char *)symtab +
  147                             shp[i].sh_offset + shp[i].sh_size);
  148                 }
  149         }
  150 
  151         /*
  152          * Now, sanity check the symbols against the string table.
  153          */
  154         if (symtab_start == NULL || strtab_start == NULL ||
  155             ALIGNED_POINTER(symtab_start, long) == 0) {
  156                 errstr = "symtab unaligned";
  157                 goto badheader;
  158         }
  159         for (symp = symtab_start; symp < symtab_end; symp++)
  160                 if (symp->st_name + strtab_start > strtab_end) {
  161                         errstr = "symtab corrupted";
  162                         goto badheader;
  163                 }
  164 
  165         /*
  166          * Link the symbol table into the debugger.
  167          */
  168         db_symtab.start = (char *)symtab_start;
  169         db_symtab.end = (char *)symtab_end;
  170         db_symtab.name = name;
  171         db_symtab.private = (char *)symtab;
  172 
  173         db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
  174             (u_long)roundup(((char *)esymtab - (char *)symtab), sizeof(u_long)),
  175             name);
  176 
  177         return (1);
  178 
  179  badheader:
  180         db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
  181         return (0);
  182 }
  183 
  184 /*
  185  * Internal helper function - return a pointer to the string table
  186  * for the current symbol table.
  187  */
  188 char *
  189 db_elf_find_strtab(db_symtab_t *stab)
  190 {
  191         Elf_Ehdr *elf = STAB_TO_EHDR(stab);
  192         Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
  193         char *shstrtab;
  194         int i;
  195 
  196         shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
  197         for (i = 0; i < elf->e_shnum; i++) {
  198                 if (shp[i].sh_type == SHT_SYMTAB)
  199                         return ((char *)elf + shp[shp[i].sh_link].sh_offset);
  200                 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
  201                         return ((char *)elf + shp[i].sh_offset);
  202         }
  203 
  204         return (NULL);
  205 }
  206 
  207 /*
  208  * Internal helper function - return a pointer to the section
  209  * named ``sname''.
  210  */
  211 const char *
  212 db_elf_find_section(db_symtab_t *stab, size_t *size, const char *sname)
  213 {
  214         Elf_Ehdr *elf = STAB_TO_EHDR(stab);
  215         Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
  216         char *shstrtab;
  217         int i;
  218 
  219         shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
  220         for (i = 0; i < elf->e_shnum; i++) {
  221                 if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
  222                     strcmp(sname, shstrtab+shp[i].sh_name) == 0) {
  223                         *size = shp[i].sh_size;
  224                         return ((char *)elf + shp[i].sh_offset);
  225                 }
  226         }
  227 
  228         return (NULL);
  229 }
  230 
  231 /*
  232  * Lookup the symbol with the given name.
  233  */
  234 Elf_Sym *
  235 db_elf_sym_lookup(char *symstr)
  236 {
  237         db_symtab_t *stab = &db_symtab;
  238         Elf_Sym *symp, *symtab_start, *symtab_end;
  239         char *strtab;
  240 
  241         if (stab->private == NULL)
  242                 return (NULL);
  243 
  244         symtab_start = STAB_TO_SYMSTART(stab);
  245         symtab_end = STAB_TO_SYMEND(stab);
  246 
  247         strtab = db_elf_find_strtab(stab);
  248         if (strtab == NULL)
  249                 return (NULL);
  250 
  251         for (symp = symtab_start; symp < symtab_end; symp++) {
  252                 if (symp->st_name != 0 &&
  253                     db_eqname(strtab + symp->st_name, symstr, 0))
  254                         return (symp);
  255         }
  256 
  257         return (NULL);
  258 }
  259 
  260 /*
  261  * Search for the symbol with the given address (matching within the
  262  * provided threshold).
  263  */
  264 Elf_Sym *
  265 db_elf_sym_search(vaddr_t off, db_strategy_t strategy, db_expr_t *diffp)
  266 {
  267         db_symtab_t *stab = &db_symtab;
  268         Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
  269         db_expr_t diff = *diffp;
  270 
  271         if (stab->private == NULL)
  272                 return (NULL);
  273 
  274         symtab_start = STAB_TO_SYMSTART(stab);
  275         symtab_end = STAB_TO_SYMEND(stab);
  276 
  277         rsymp = NULL;
  278 
  279         for (symp = symtab_start; symp < symtab_end; symp++) {
  280                 if (symp->st_name == 0)
  281                         continue;
  282 #if 0
  283                 /* This prevents me from seeing anythin in locore.s -- eeh */
  284                 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
  285                     ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
  286                         continue;
  287 #endif
  288 
  289                 if (off >= symp->st_value) {
  290                         if ((off - symp->st_value) < diff) {
  291                                 diff = off - symp->st_value;
  292                                 rsymp = symp;
  293                                 if (diff == 0) {
  294                                         if (strategy == DB_STGY_PROC &&
  295                                             ELF_ST_TYPE(symp->st_info)
  296                                               == STT_FUNC &&
  297                                             ELF_ST_BIND(symp->st_info)
  298                                               != STB_LOCAL)
  299                                                 break;
  300                                         if (strategy == DB_STGY_ANY &&
  301                                             ELF_ST_BIND(symp->st_info)
  302                                               != STB_LOCAL)
  303                                                 break;
  304                                 }
  305                         } else if ((off - symp->st_value) == diff) {
  306                                 if (rsymp == NULL)
  307                                         rsymp = symp;
  308                                 else if (ELF_ST_BIND(rsymp->st_info)
  309                                       == STB_LOCAL &&
  310                                     ELF_ST_BIND(symp->st_info)
  311                                       != STB_LOCAL) {
  312                                         /* pick the external symbol */
  313                                         rsymp = symp;
  314                                 }
  315                         }
  316                 }
  317         }
  318 
  319         if (rsymp == NULL)
  320                 *diffp = off;
  321         else
  322                 *diffp = diff;
  323 
  324         return (rsymp);
  325 }
  326 
  327 /*
  328  * Return the name and value for a symbol.
  329  */
  330 void
  331 db_symbol_values(Elf_Sym *sym, char **namep, db_expr_t *valuep)
  332 {
  333         db_symtab_t *stab = &db_symtab;
  334         Elf_Sym *symp = (Elf_Sym *)sym;
  335         char *strtab;
  336 
  337         if (sym == NULL) {
  338                 *namep = NULL;
  339                 return;
  340         }
  341 
  342         if (stab->private == NULL)
  343                 return;
  344 
  345         if (namep) {
  346                 strtab = db_elf_find_strtab(stab);
  347                 if (strtab == NULL)
  348                         *namep = NULL;
  349                 else
  350                         *namep = strtab + symp->st_name;
  351         }
  352 
  353         if (valuep)
  354                 *valuep = symp->st_value;
  355 }
  356 
  357 /*
  358  * Return the file and line number of the current program counter
  359  * if we can find the appropriate debugging symbol.
  360  */
  361 int
  362 db_elf_line_at_pc(Elf_Sym *cursym, char **filename,
  363     int *linenum, db_expr_t off)
  364 {
  365         db_symtab_t *stab = &db_symtab;
  366         static char path[PATH_MAX];
  367         const char *linetab, *dirname, *basename;
  368         size_t linetab_size;
  369 
  370         if (stab->private == NULL)
  371                 return (0);
  372 
  373         linetab = db_elf_find_section(stab, &linetab_size, ".debug_line");
  374         if (linetab == NULL)
  375                 return (0);
  376 
  377         if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
  378             &dirname, &basename, linenum))
  379                 return (0);
  380 
  381         if (dirname == NULL)
  382                 strlcpy(path, basename, sizeof(path));
  383         else
  384                 snprintf(path, sizeof(path), "%s/%s", dirname, basename);
  385         *filename = path;
  386         return (1);
  387 }
  388 
  389 void
  390 db_elf_sym_forall(db_forall_func_t db_forall_func, void *arg)
  391 {
  392         db_symtab_t *stab = &db_symtab;
  393         char *strtab;
  394         static char suffix[2];
  395         Elf_Sym *symp, *symtab_start, *symtab_end;
  396 
  397         if (stab->private == NULL)
  398                 return;
  399 
  400         symtab_start = STAB_TO_SYMSTART(stab);
  401         symtab_end = STAB_TO_SYMEND(stab);
  402 
  403         strtab = db_elf_find_strtab(stab);
  404         if (strtab == NULL)
  405                 return;
  406 
  407         for (symp = symtab_start; symp < symtab_end; symp++)
  408                 if (symp->st_name != 0) {
  409                         suffix[1] = '\0';
  410                         switch (ELF_ST_TYPE(symp->st_info)) {
  411                         case STT_OBJECT:
  412                                 suffix[0] = '+';
  413                                 break;
  414                         case STT_FUNC:
  415                                 suffix[0] = '*';
  416                                 break;
  417                         case STT_SECTION:
  418                                 suffix[0] = '&';
  419                                 break;
  420                         case STT_FILE:
  421                                 suffix[0] = '/';
  422                                 break;
  423                         default:
  424                                 suffix[0] = '\0';
  425                         }
  426                         (*db_forall_func)(symp,
  427                             strtab + symp->st_name, suffix, 0, arg);
  428                 }
  429 }
  430 
  431 Elf_Sym *
  432 db_symbol_by_name(char *name, db_expr_t *valuep)
  433 {
  434         Elf_Sym         *sym;
  435 
  436         sym = db_elf_sym_lookup(name);
  437         if (sym == NULL)
  438                 return (NULL);
  439         db_symbol_values(sym, &name, valuep);
  440         return (sym);
  441 }

Cache object: 7da2b6ef92d7a7677748e04ef87a0759


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