source: mainline/kernel/generic/src/debug/symtab.c

Last change on this file was 40eab9f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 21 months ago

Print symbol names and line numbers in stacktraces for init tasks

Only useful in select few situations, but useful nonetheless.

  • Property mode set to 100644
File size: 5.8 KB
RevLine 
[ab08b42]1/*
[df4ed85]2 * Copyright (c) 2005 Ondrej Palkovsky
[ab08b42]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[174156fd]29/** @addtogroup kernel_generic_debug
[b45c443]30 * @{
31 */
32
[cf26ba9]33/**
[b45c443]34 * @file
[68ad9d2]35 * @brief Kernel symbol resolver.
[cf26ba9]36 */
[ab08b42]37
[40eab9f]38#include <abi/elf.h>
[5d494b3]39#include <byteorder.h>
[f0d7bd9]40#include <console/prompt.h>
[da13982]41#include <debug/sections.h>
[40eab9f]42#include <errno.h>
43#include <proc/task.h>
44#include <stdio.h>
45#include <str.h>
46#include <symtab.h>
47#include <typedefs.h>
[da13982]48
[40eab9f]49static inline const char *symtab_entry_name(debug_sections_t *scs, int entry)
[da13982]50{
[40eab9f]51 size_t index = scs->symtab[entry].st_name;
[da13982]52
[40eab9f]53 if (index >= scs->strtab_size)
[da13982]54 return NULL;
55
[40eab9f]56 return scs->strtab + index;
[da13982]57}
58
[40eab9f]59static inline size_t symtab_next(debug_sections_t *scs, size_t i)
[ab08b42]60{
[40eab9f]61 size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
62
63 for (; i < symtab_len; i++) {
64 const char *name = symtab_entry_name(scs, i);
65 int st_bind = elf_st_bind(scs->symtab[i].st_info);
66 int st_type = elf_st_type(scs->symtab[i].st_info);
[a35b458]67
[da13982]68 if (st_bind == STB_LOCAL)
69 continue;
70
71 if (name == NULL || *name == '\0')
72 continue;
73
74 if (st_type == STT_FUNC || st_type == STT_OBJECT)
[ab08b42]75 break;
76 }
[a35b458]77
[da13982]78 return i;
79}
80
[40eab9f]81const char *symtab_name_lookup(uintptr_t addr, uintptr_t *symbol_addr, debug_sections_t *scs)
[da13982]82{
[40eab9f]83 const elf_symbol_t *symtab = scs->symtab;
84 size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
85 const char *strtab = scs->strtab;
86 size_t strtab_size = scs->strtab_size;
87
[da13982]88 if (symtab == NULL || strtab == NULL)
89 return NULL;
90
91 uintptr_t closest_symbol_addr = 0;
92 uintptr_t closest_symbol_name = 0;
93
[40eab9f]94 for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
[da13982]95 if (symtab[i].st_value > addr)
96 continue;
97
98 if (symtab[i].st_value + symtab[i].st_size > addr) {
99 closest_symbol_addr = symtab[i].st_value;
100 closest_symbol_name = symtab[i].st_name;
101 break;
102 }
103
104 if (symtab[i].st_value > closest_symbol_addr) {
105 closest_symbol_addr = symtab[i].st_value;
106 closest_symbol_name = symtab[i].st_name;
107 }
[e16e0d59]108 }
[a35b458]109
[da13982]110 if (closest_symbol_addr == 0)
111 return NULL;
112
113 if (symbol_addr)
114 *symbol_addr = closest_symbol_addr;
115
116 if (closest_symbol_name >= strtab_size)
117 return NULL;
[a35b458]118
[da13982]119 return strtab + closest_symbol_name;
[e16e0d59]120}
121
122/** Lookup symbol by address and format for display.
123 *
[c19aa612]124 * Returns name of closest corresponding symbol,
125 * "unknown" if none exists and "N/A" if no symbol
126 * information is available.
[e16e0d59]127 *
[68ad9d2]128 * @param addr Address.
129 * @param name Place to store pointer to the symbol name.
130 *
131 * @return Pointer to a human-readable string.
[e16e0d59]132 *
133 */
[a000878c]134const char *symtab_fmt_name_lookup(uintptr_t addr)
[e16e0d59]135{
[40eab9f]136 const char *name = symtab_name_lookup(addr, NULL, &kernel_sections);
[da13982]137 if (name == NULL)
138 name = "<unknown>";
139 return name;
[ab08b42]140}
[6e716a59]141
[68ad9d2]142/** Return address that corresponds to the entry.
[6e716a59]143 *
[0c8e692]144 * Search symbol table, and if there is one match, return it
[6e716a59]145 *
[68ad9d2]146 * @param name Name of the symbol
147 * @param addr Place to store symbol address
148 *
[da13982]149 * @return Zero on success, ENOENT - not found
[e16e0d59]150 *
[6e716a59]151 */
[b7fd2a0]152errno_t symtab_addr_lookup(const char *name, uintptr_t *addr)
[6e716a59]153{
[40eab9f]154 debug_sections_t *scs = &kernel_sections;
155 size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
156
157 for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
158 if (str_cmp(name, symtab_entry_name(scs, i)) == 0) {
159 *addr = scs->symtab[i].st_value;
[da13982]160 return EOK;
[6e716a59]161 }
162 }
[a35b458]163
[da13982]164 return ENOENT;
[6e716a59]165}
166
[68ad9d2]167/** Find symbols that match parameter and print them */
[6e716a59]168void symtab_print_search(const char *name)
169{
[40eab9f]170 debug_sections_t *scs = &kernel_sections;
171 size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
172
173 if (scs->symtab == NULL || scs->strtab == NULL) {
[da13982]174 printf("No symbol information available.\n");
175 return;
[0c8e692]176 }
[a35b458]177
[da13982]178 size_t namelen = str_length(name);
179
[40eab9f]180 for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
181 const char *n = symtab_entry_name(scs, i);
[da13982]182
183 if (str_lcmp(name, n, namelen) == 0) {
[40eab9f]184 printf("%p: %s\n", (void *) scs->symtab[i].st_value, n);
[da13982]185 }
186 }
[0c8e692]187}
188
[a363016]189/** Symtab completion enum, see kernel/generic/include/kconsole.h */
[da13982]190const char *symtab_hints_enum(const char *input, const char **help, void **ctx)
[0c8e692]191{
[40eab9f]192 debug_sections_t *scs = &kernel_sections;
193 size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
194
195 if (scs->symtab == NULL || scs->strtab == NULL)
[da13982]196 return NULL;
[a35b458]197
[da13982]198 if (help)
199 *help = NULL;
[a35b458]200
[da13982]201 size_t len = str_length(input);
[40eab9f]202 for (size_t i = symtab_next(scs, (size_t) *ctx); i < symtab_len; i = symtab_next(scs, i + 1)) {
203 const char *curname = symtab_entry_name(scs, i);
[a35b458]204
[a363016]205 if (str_lcmp(input, curname, len) == 0) {
[da13982]206 *ctx = (void *) (i + 1);
[a363016]207 return (curname + str_lsize(curname, len));
208 }
[6e716a59]209 }
[a35b458]210
[a363016]211 return NULL;
[6e716a59]212}
[b45c443]213
[06e1e95]214/** @}
[b45c443]215 */
Note: See TracBrowser for help on using the repository browser.