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

Last change on this file was 40eab9f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 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
Line 
1/*
2 * Copyright (c) 2005 Ondrej Palkovsky
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
29/** @addtogroup kernel_generic_debug
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Kernel symbol resolver.
36 */
37
38#include <abi/elf.h>
39#include <byteorder.h>
40#include <console/prompt.h>
41#include <debug/sections.h>
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>
48
49static inline const char *symtab_entry_name(debug_sections_t *scs, int entry)
50{
51 size_t index = scs->symtab[entry].st_name;
52
53 if (index >= scs->strtab_size)
54 return NULL;
55
56 return scs->strtab + index;
57}
58
59static inline size_t symtab_next(debug_sections_t *scs, size_t i)
60{
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);
67
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)
75 break;
76 }
77
78 return i;
79}
80
81const char *symtab_name_lookup(uintptr_t addr, uintptr_t *symbol_addr, debug_sections_t *scs)
82{
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
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
94 for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
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 }
108 }
109
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;
118
119 return strtab + closest_symbol_name;
120}
121
122/** Lookup symbol by address and format for display.
123 *
124 * Returns name of closest corresponding symbol,
125 * "unknown" if none exists and "N/A" if no symbol
126 * information is available.
127 *
128 * @param addr Address.
129 * @param name Place to store pointer to the symbol name.
130 *
131 * @return Pointer to a human-readable string.
132 *
133 */
134const char *symtab_fmt_name_lookup(uintptr_t addr)
135{
136 const char *name = symtab_name_lookup(addr, NULL, &kernel_sections);
137 if (name == NULL)
138 name = "<unknown>";
139 return name;
140}
141
142/** Return address that corresponds to the entry.
143 *
144 * Search symbol table, and if there is one match, return it
145 *
146 * @param name Name of the symbol
147 * @param addr Place to store symbol address
148 *
149 * @return Zero on success, ENOENT - not found
150 *
151 */
152errno_t symtab_addr_lookup(const char *name, uintptr_t *addr)
153{
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;
160 return EOK;
161 }
162 }
163
164 return ENOENT;
165}
166
167/** Find symbols that match parameter and print them */
168void symtab_print_search(const char *name)
169{
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) {
174 printf("No symbol information available.\n");
175 return;
176 }
177
178 size_t namelen = str_length(name);
179
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);
182
183 if (str_lcmp(name, n, namelen) == 0) {
184 printf("%p: %s\n", (void *) scs->symtab[i].st_value, n);
185 }
186 }
187}
188
189/** Symtab completion enum, see kernel/generic/include/kconsole.h */
190const char *symtab_hints_enum(const char *input, const char **help, void **ctx)
191{
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)
196 return NULL;
197
198 if (help)
199 *help = NULL;
200
201 size_t len = str_length(input);
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);
204
205 if (str_lcmp(input, curname, len) == 0) {
206 *ctx = (void *) (i + 1);
207 return (curname + str_lsize(curname, len));
208 }
209 }
210
211 return NULL;
212}
213
214/** @}
215 */
Note: See TracBrowser for help on using the repository browser.