Changeset da13982 in mainline for kernel/generic/src/debug/symtab.c


Ignore:
Timestamp:
2023-10-26T15:20:07Z (15 months ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master, topic/msim-upgrade, topic/simplify-dev-export
Children:
2fbb42f
Parents:
d28bdbe
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2023-10-26 14:42:03)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2023-10-26 15:20:07)
Message:

Read symbol table from ELF sections

Instead of the currently broken data generated using genmap.py,
read the ELF symbol table for stack traces and symbol names.
In addition to that, prepare ground for accessing DWARF debug
sections.

Because neither .symtab, nor .debug_* sections are
normally part of the program image, these have to be provided
externally. Instead of the previous way of relinking kernel
to bake in the symbol data, we now only link kernel once
and the extra debug data is loaded as part of the initrd image.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/debug/symtab.c

    rd28bdbe rda13982  
    4444#include <console/prompt.h>
    4545
    46 /** Get name of a symbol that seems most likely to correspond to address.
    47  *
    48  * @param addr   Address.
    49  * @param name   Place to store pointer to the symbol name.
    50  * @param offset Place to store offset from the symbol address.
    51  *
    52  * @return Zero on success or an error code, ENOENT if not found,
    53  *         ENOTSUP if symbol table not available.
    54  *
    55  */
    56 errno_t symtab_name_lookup(uintptr_t addr, const char **name, uintptr_t *offset)
    57 {
    58 #ifdef CONFIG_SYMTAB
    59         size_t i;
    60 
    61         for (i = 1; symbol_table[i].address_le; i++) {
    62                 if (addr < uint64_t_le2host(symbol_table[i].address_le))
     46#include <abi/elf.h>
     47#include <debug/sections.h>
     48
     49static inline size_t symtab_len()
     50{
     51        return symtab_size / sizeof(elf_symbol_t);
     52}
     53
     54static inline const char *symtab_entry_name(int entry)
     55{
     56        size_t index = symtab[entry].st_name;
     57
     58        if (index >= strtab_size)
     59                return NULL;
     60
     61        return strtab + index;
     62}
     63
     64static inline size_t symtab_next(size_t i)
     65{
     66        for (; i < symtab_len(); i++) {
     67                const char *name = symtab_entry_name(i);
     68                int st_bind = elf_st_bind(symtab[i].st_info);
     69                int st_type = elf_st_type(symtab[i].st_info);
     70
     71                if (st_bind == STB_LOCAL)
     72                        continue;
     73
     74                if (name == NULL || *name == '\0')
     75                        continue;
     76
     77                if (st_type == STT_FUNC || st_type == STT_OBJECT)
    6378                        break;
    6479        }
    6580
    66         if (addr >= uint64_t_le2host(symbol_table[i - 1].address_le)) {
    67                 *name = symbol_table[i - 1].symbol_name;
    68                 if (offset)
    69                         *offset = addr -
    70                             uint64_t_le2host(symbol_table[i - 1].address_le);
    71                 return EOK;
    72         }
    73 
    74         *name = NULL;
    75         return ENOENT;
    76 
    77 #else
    78         *name = NULL;
    79         return ENOTSUP;
    80 #endif
     81        return i;
     82}
     83
     84const char *symtab_name_lookup(uintptr_t addr, uintptr_t *symbol_addr)
     85{
     86        if (symtab == NULL || strtab == NULL)
     87                return NULL;
     88
     89        uintptr_t closest_symbol_addr = 0;
     90        uintptr_t closest_symbol_name = 0;
     91
     92        for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
     93                if (symtab[i].st_value > addr)
     94                        continue;
     95
     96                if (symtab[i].st_value + symtab[i].st_size > addr) {
     97                        closest_symbol_addr = symtab[i].st_value;
     98                        closest_symbol_name = symtab[i].st_name;
     99                        break;
     100                }
     101
     102                if (symtab[i].st_value > closest_symbol_addr) {
     103                        closest_symbol_addr = symtab[i].st_value;
     104                        closest_symbol_name = symtab[i].st_name;
     105                }
     106        }
     107
     108        if (closest_symbol_addr == 0)
     109                return NULL;
     110
     111        if (symbol_addr)
     112                *symbol_addr = closest_symbol_addr;
     113
     114        if (closest_symbol_name >= strtab_size)
     115                return NULL;
     116
     117        return strtab + closest_symbol_name;
    81118}
    82119
     
    95132const char *symtab_fmt_name_lookup(uintptr_t addr)
    96133{
    97         const char *name;
    98         errno_t rc = symtab_name_lookup(addr, &name, NULL);
    99 
    100         switch (rc) {
    101         case EOK:
    102                 return name;
    103         case ENOENT:
    104                 return "unknown";
    105         default:
    106                 return "N/A";
    107         }
    108 }
    109 
    110 #ifdef CONFIG_SYMTAB
    111 
    112 /** Find symbols that match the parameter forward and print them.
    113  *
    114  * @param name     Search string
    115  * @param startpos Starting position, changes to found position
    116  *
    117  * @return Pointer to the part of string that should be completed or NULL.
    118  *
    119  */
    120 static const char *symtab_search_one(const char *name, size_t *startpos)
    121 {
    122         size_t namelen = str_length(name);
    123 
    124         size_t pos;
    125         for (pos = *startpos; symbol_table[pos].address_le; pos++) {
    126                 const char *curname = symbol_table[pos].symbol_name;
    127 
    128                 /* Find a ':' in curname */
    129                 const char *colon = str_chr(curname, ':');
    130                 if (colon == NULL)
    131                         continue;
    132 
    133                 if (str_length(curname) < namelen)
    134                         continue;
    135 
    136                 if (str_lcmp(name, curname, namelen) == 0) {
    137                         *startpos = pos;
    138                         return (curname + str_lsize(curname, namelen));
    139                 }
    140         }
    141 
    142         return NULL;
    143 }
    144 
    145 #endif
     134        const char *name = symtab_name_lookup(addr, NULL);
     135        if (name == NULL)
     136                name = "<unknown>";
     137        return name;
     138}
    146139
    147140/** Return address that corresponds to the entry.
     
    152145 * @param addr Place to store symbol address
    153146 *
    154  * @return Zero on success, ENOENT - not found, EOVERFLOW - duplicate
    155  *         symbol, ENOTSUP - no symbol information available.
     147 * @return Zero on success, ENOENT - not found
    156148 *
    157149 */
    158150errno_t symtab_addr_lookup(const char *name, uintptr_t *addr)
    159151{
    160 #ifdef CONFIG_SYMTAB
    161         size_t found = 0;
    162         size_t pos = 0;
    163         const char *hint;
    164 
    165         while ((hint = symtab_search_one(name, &pos))) {
    166                 if (str_length(hint) == 0) {
    167                         *addr = uint64_t_le2host(symbol_table[pos].address_le);
    168                         found++;
    169                 }
    170                 pos++;
    171         }
    172 
    173         if (found > 1)
    174                 return EOVERFLOW;
    175 
    176         if (found < 1)
    177                 return ENOENT;
    178 
    179         return EOK;
    180 
    181 #else
    182         return ENOTSUP;
    183 #endif
     152        for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
     153                if (str_cmp(name, symtab_entry_name(i)) == 0) {
     154                        *addr = symtab[i].st_value;
     155                        return EOK;
     156                }
     157        }
     158
     159        return ENOENT;
    184160}
    185161
     
    187163void symtab_print_search(const char *name)
    188164{
    189 #ifdef CONFIG_SYMTAB
    190         size_t pos = 0;
    191         while (symtab_search_one(name, &pos)) {
    192                 uintptr_t addr = uint64_t_le2host(symbol_table[pos].address_le);
    193                 char *realname = symbol_table[pos].symbol_name;
    194                 printf("%p: %s\n", (void *) addr, realname);
    195                 pos++;
    196         }
    197 
    198 #else
    199         printf("No symbol information available.\n");
    200 #endif
     165        if (symtab == NULL || strtab == NULL) {
     166                printf("No symbol information available.\n");
     167                return;
     168        }
     169
     170        size_t namelen = str_length(name);
     171
     172        for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
     173                const char *n = symtab_entry_name(i);
     174
     175                if (str_lcmp(name, n, namelen) == 0) {
     176                        printf("%p: %s\n", (void *) symtab[i].st_value, n);
     177                }
     178        }
    201179}
    202180
    203181/** Symtab completion enum, see kernel/generic/include/kconsole.h */
    204 const char *symtab_hints_enum(const char *input, const char **help,
    205     void **ctx)
    206 {
    207 #ifdef CONFIG_SYMTAB
     182const char *symtab_hints_enum(const char *input, const char **help, void **ctx)
     183{
     184        if (symtab == NULL || strtab == NULL)
     185                return NULL;
     186
     187        if (help)
     188                *help = NULL;
     189
    208190        size_t len = str_length(input);
    209         struct symtab_entry **entry = (struct symtab_entry **)ctx;
    210 
    211         if (*entry == NULL)
    212                 *entry = symbol_table;
    213 
    214         for (; (*entry)->address_le; (*entry)++) {
    215                 const char *curname = (*entry)->symbol_name;
    216 
    217                 /* Find a ':' in curname */
    218                 const char *colon = str_chr(curname, ':');
    219                 if (colon == NULL)
    220                         continue;
    221 
    222                 if (str_length(curname) < len)
    223                         continue;
     191        for (size_t i = symtab_next((size_t) *ctx); i < symtab_len(); i = symtab_next(i + 1)) {
     192                const char *curname = symtab_entry_name(i);
    224193
    225194                if (str_lcmp(input, curname, len) == 0) {
    226                         (*entry)++;
    227                         if (help)
    228                                 *help = NULL;
     195                        *ctx = (void *) (i + 1);
    229196                        return (curname + str_lsize(curname, len));
    230197                }
     
    232199
    233200        return NULL;
    234 
    235 #else
    236         return NULL;
    237 #endif
    238201}
    239202
Note: See TracChangeset for help on using the changeset viewer.