source: mainline/uspace/app/taskdump/symtab.c@ b8b64a8

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b8b64a8 was ca0e838, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Convert preprocessor macros in abi/ to C constructs

Preprocessor macros are an obsolete concept and they complicate things.
They are also completely unnecessary in most circumstances.

This commit changes untyped numeric constants into anonymous enums,
typed constants into static const variables, and function-like macros
into functions.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
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 debug
30 * @{
31 */
32/** @file Handling of ELF symbol tables.
33 *
34 * This module allows one to load a symbol table from an ELF file and
35 * use it to lookup symbol names/addresses in both directions.
36 */
37
38#include <elf/elf.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <stddef.h>
42#include <errno.h>
43#include <str.h>
44#include <str_error.h>
45#include <vfs/vfs.h>
46
47#include "include/symtab.h"
48
49static errno_t elf_hdr_check(elf_header_t *hdr);
50static errno_t section_hdr_load(int fd, const elf_header_t *ehdr, int idx,
51 elf_section_header_t *shdr);
52static errno_t chunk_load(int fd, off64_t start, size_t size, void **ptr);
53
54/** Load symbol table from an ELF file.
55 *
56 * @param file_name Name of the ELF file to read from.
57 * @param symtab Place to save pointer to new symtab structure.
58 *
59 * @return EOK on success, ENOENT if file could not be open,
60 * ENOTSUP if file parsing failed.
61 */
62errno_t symtab_load(const char *file_name, symtab_t **symtab)
63{
64 symtab_t *stab;
65 elf_header_t elf_hdr;
66 elf_section_header_t sec_hdr;
67 off64_t shstrt_start;
68 size_t shstrt_size;
69 char *shstrt, *sec_name;
70 void *data;
71 aoff64_t pos = 0;
72
73 int fd;
74 errno_t rc;
75 size_t nread;
76 int i;
77
78 bool load_sec, sec_is_symtab;
79
80 *symtab = NULL;
81
82 stab = calloc(1, sizeof(symtab_t));
83 if (stab == NULL)
84 return ENOMEM;
85
86 rc = vfs_lookup_open(file_name, WALK_REGULAR, MODE_READ, &fd);
87 if (rc != EOK) {
88 printf("failed opening file '%s': %s\n", file_name, str_error(rc));
89 free(stab);
90 return ENOENT;
91 }
92
93 rc = vfs_read(fd, &pos, &elf_hdr, sizeof(elf_header_t), &nread);
94 if (rc != EOK || nread != sizeof(elf_header_t)) {
95 printf("failed reading elf header\n");
96 free(stab);
97 return EIO;
98 }
99
100 rc = elf_hdr_check(&elf_hdr);
101 if (rc != EOK) {
102 printf("failed header check\n");
103 free(stab);
104 return ENOTSUP;
105 }
106
107 /*
108 * Load section header string table.
109 */
110
111 rc = section_hdr_load(fd, &elf_hdr, elf_hdr.e_shstrndx, &sec_hdr);
112 if (rc != EOK) {
113 printf("failed reading shstrt header\n");
114 free(stab);
115 return ENOTSUP;
116 }
117
118 shstrt_start = sec_hdr.sh_offset;
119 shstrt_size = sec_hdr.sh_size;
120
121 rc = chunk_load(fd, shstrt_start, shstrt_size, (void **) &shstrt);
122 if (rc != EOK) {
123 printf("failed loading shstrt\n");
124 free(stab);
125 return ENOTSUP;
126 }
127
128 /* Read all section headers. */
129 for (i = 0; i < elf_hdr.e_shnum; ++i) {
130 rc = section_hdr_load(fd, &elf_hdr, i, &sec_hdr);
131 if (rc != EOK) {
132 free(shstrt);
133 free(stab);
134 return ENOTSUP;
135 }
136
137 sec_name = shstrt + sec_hdr.sh_name;
138 if (str_cmp(sec_name, ".symtab") == 0 &&
139 sec_hdr.sh_type == SHT_SYMTAB) {
140 load_sec = true;
141 sec_is_symtab = true;
142 } else if (str_cmp(sec_name, ".strtab") == 0 &&
143 sec_hdr.sh_type == SHT_STRTAB) {
144 load_sec = true;
145 sec_is_symtab = false;
146 } else {
147 load_sec = false;
148 }
149
150 if (load_sec) {
151 rc = chunk_load(fd, sec_hdr.sh_offset, sec_hdr.sh_size,
152 &data);
153 if (rc != EOK) {
154 free(shstrt);
155 free(stab);
156 return ENOTSUP;
157 }
158
159 if (sec_is_symtab) {
160 stab->sym = data;
161 stab->sym_size = sec_hdr.sh_size;
162 } else {
163 stab->strtab = data;
164 stab->strtab_size = sec_hdr.sh_size;
165 }
166 }
167 }
168
169 free(shstrt);
170 vfs_put(fd);
171
172 if (stab->sym == NULL || stab->strtab == NULL) {
173 /* Tables not found. */
174 printf("Symbol table or string table section not found\n");
175 free(stab);
176 return ENOTSUP;
177 }
178
179 *symtab = stab;
180
181 return EOK;
182}
183
184/** Delete a symtab structure.
185 *
186 * Deallocates all resources used by the symbol table.
187 */
188void symtab_delete(symtab_t *st)
189{
190 free(st->sym);
191 st->sym = NULL;
192
193 free(st->strtab);
194 st->strtab = NULL;
195
196 free(st);
197}
198
199/** Convert symbol name to address.
200 *
201 * @param st Symbol table.
202 * @param name Name of the symbol.
203 * @param addr Place to store address for symbol, if found.
204 *
205 * @return EOK on success, ENOENT if no such symbol was found.
206 */
207errno_t symtab_name_to_addr(symtab_t *st, const char *name, uintptr_t *addr)
208{
209 size_t i;
210 char *sname;
211 unsigned stype;
212
213 for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
214 if (st->sym[i].st_name == 0)
215 continue;
216
217 stype = elf_st_type(st->sym[i].st_info);
218 if (stype != STT_OBJECT && stype != STT_FUNC)
219 continue;
220
221 sname = st->strtab + st->sym[i].st_name;
222
223 if (str_cmp(sname, name) == 0) {
224 *addr = st->sym[i].st_value;
225 return EOK;
226 }
227 }
228
229 return ENOENT;
230}
231
232/** Convert symbol address to name.
233 *
234 * This function finds the symbol which starts at the highest address
235 * less than or equal to @a addr.
236 *
237 * @param st Symbol table.
238 * @param addr Address for lookup.
239 * @param name Place to store pointer name of symbol, if found.
240 * This is valid while @a st exists.
241 *
242 * @return EOK on success or ENOENT if no matching symbol was found.
243 */
244errno_t symtab_addr_to_name(symtab_t *st, uintptr_t addr, char **name,
245 size_t *offs)
246{
247 size_t i;
248 uintptr_t saddr, best_addr;
249 char *sname, *best_name;
250 unsigned stype;
251
252 best_name = NULL;
253 best_addr = 0;
254
255 for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
256 if (st->sym[i].st_name == 0)
257 continue;
258
259 stype = elf_st_type(st->sym[i].st_info);
260 if (stype != STT_OBJECT && stype != STT_FUNC &&
261 stype != STT_NOTYPE) {
262 continue;
263 }
264
265 saddr = st->sym[i].st_value;
266 sname = st->strtab + st->sym[i].st_name;
267
268 /* An ugly hack to filter out some special ARM symbols. */
269 if (sname[0] == '$')
270 continue;
271
272 if (saddr <= addr && (best_name == NULL || saddr > best_addr)) {
273 best_name = sname;
274 best_addr = saddr;
275 }
276 }
277
278 if (best_name == NULL)
279 return ENOENT;
280
281 *name = best_name;
282 *offs = addr - best_addr;
283 return EOK;
284}
285
286/** Check if ELF header is valid.
287 *
288 * @return EOK on success or an error code.
289 */
290static errno_t elf_hdr_check(elf_header_t *ehdr)
291{
292 /* TODO */
293 return EOK;
294}
295
296/** Load ELF section header.
297 *
298 * @param fd File descriptor of ELF file.
299 * @param elf_hdr Pointer to ELF file header in memory.
300 * @param idx Index of section whose header to load (0 = first).
301 * @param sec_hdr Place to store section header data.
302 *
303 * @return EOK on success or EIO if I/O failed.
304 */
305static errno_t section_hdr_load(int fd, const elf_header_t *elf_hdr, int idx,
306 elf_section_header_t *sec_hdr)
307{
308 errno_t rc;
309 size_t nread;
310 aoff64_t pos = elf_hdr->e_shoff + idx * sizeof(elf_section_header_t);
311
312 rc = vfs_read(fd, &pos, sec_hdr, sizeof(elf_section_header_t), &nread);
313 if (rc != EOK || nread != sizeof(elf_section_header_t))
314 return EIO;
315
316 return EOK;
317}
318
319/** Load a segment of bytes from a file and return it as a new memory block.
320 *
321 * This function fails if it cannot read exactly @a size bytes from the file.
322 *
323 * @param fd File to read from.
324 * @param start Position in file where to start reading.
325 * @param size Number of bytes to read.
326 * @param ptr Place to store pointer to newly allocated block.
327 *
328 * @return EOK on success or EIO on failure.
329 */
330static errno_t chunk_load(int fd, off64_t start, size_t size, void **ptr)
331{
332 errno_t rc;
333 size_t nread;
334 aoff64_t pos = start;
335
336 *ptr = malloc(size);
337 if (*ptr == NULL) {
338 printf("failed allocating memory\n");
339 return ENOMEM;
340 }
341
342 rc = vfs_read(fd, &pos, *ptr, size, &nread);
343 if (rc != EOK || nread != size) {
344 printf("failed reading chunk\n");
345 free(*ptr);
346 *ptr = NULL;
347 return EIO;
348 }
349
350 return EOK;
351}
352
353/** @}
354 */
Note: See TracBrowser for help on using the repository browser.