1/*
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include <unistd.h>
26#include <sys/procfs.h>
27#include <search.h>
28#include <stdlib.h>
29#include <string.h>
30#include "symtab.h"
31#include "salibelf.h"
32
33
34// ----------------------------------------------------
35// functions for symbol lookups
36// ----------------------------------------------------
37
38struct elf_section {
39 ELF_SHDR *c_shdr;
40 void *c_data;
41};
42
43struct elf_symbol {
44 char *name;
45 uintptr_t offset;
46 uintptr_t size;
47};
48
49typedef struct symtab {
50 char *strs;
51 size_t num_symbols;
52 struct elf_symbol *symbols;
53 struct hsearch_data *hash_table;
54} symtab_t;
55
56
57// Directory that contains global debuginfo files. In theory it
58// should be possible to change this, but in a Java environment there
59// is no obvious place to put a user interface to do it. Maybe this
60// could be set with an environment variable.
61static const char debug_file_directory[] = "/usr/lib/debug";
62
63/* The CRC used in gnu_debuglink, retrieved from
64 http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */
65unsigned int gnu_debuglink_crc32 (unsigned int crc,
66 unsigned char *buf, size_t len)
67{
68 static const unsigned int crc32_table[256] =
69 {
70 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
71 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
72 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
73 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
74 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
75 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
76 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
77 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
78 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
79 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
80 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
81 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
82 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
83 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
84 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
85 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
86 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
87 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
88 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
89 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
90 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
91 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
92 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
93 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
94 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
95 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
96 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
97 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
98 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
99 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
100 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
101 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
102 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
103 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
104 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
105 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
106 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
107 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
108 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
109 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
110 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
111 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
112 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
113 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
114 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
115 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
116 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
117 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
118 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
119 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
120 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
121 0x2d02ef8d
122 };
123 unsigned char *end;
124
125 crc = ~crc & 0xffffffff;
126 for (end = buf + len; buf < end; ++buf)
127 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
128 return ~crc & 0xffffffff;
129}
130
131/* Open a debuginfo file and check its CRC. If it exists and the CRC
132 matches return its fd. */
133static int
134open_debug_file (const char *pathname, unsigned int crc)
135{
136 unsigned int file_crc = 0;
137 unsigned char buffer[8 * 1024];
138
139 int fd = pathmap_open(pathname);
140
141 if (fd < 0)
142 return -1;
143
144 lseek(fd, 0, SEEK_SET);
145
146 for (;;) {
147 int len = read(fd, buffer, sizeof buffer);
148 if (len <= 0)
149 break;
150 file_crc = gnu_debuglink_crc32(file_crc, buffer, len);
151 }
152
153 if (crc == file_crc)
154 return fd;
155 else {
156 close(fd);
157 return -1;
158 }
159}
160
161/* Find an ELF section. */
162static struct elf_section *find_section_by_name(char *name,
163 int fd,
164 ELF_EHDR *ehdr,
165 struct elf_section *scn_cache)
166{
167 char *strtab;
168 int cnt;
169 int strtab_size;
170
171 // Section cache have to already contain data for e_shstrndx section.
172 // If it's not true - elf file is broken, so just bail out
173 if (scn_cache[ehdr->e_shstrndx].c_data == NULL) {
174 return NULL;
175 }
176
177 strtab = scn_cache[ehdr->e_shstrndx].c_data;
178 strtab_size = scn_cache[ehdr->e_shstrndx].c_shdr->sh_size;
179
180 for (cnt = 0; cnt < ehdr->e_shnum; ++cnt) {
181 if (scn_cache[cnt].c_shdr->sh_name < strtab_size) {
182 if (strcmp(scn_cache[cnt].c_shdr->sh_name + strtab, name) == 0) {
183 scn_cache[cnt].c_data = read_section_data(fd, ehdr, scn_cache[cnt].c_shdr);
184 return &scn_cache[cnt];
185 }
186 }
187 }
188
189 return NULL;
190}
191
192/* Look for a ".gnu_debuglink" section. If one exists, try to open a
193 suitable debuginfo file. */
194static int open_file_from_debug_link(const char *name,
195 int fd,
196 ELF_EHDR *ehdr,
197 struct elf_section *scn_cache)
198{
199 int debug_fd;
200 struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr,
201 scn_cache);
202 if (debug_link == NULL)
203 return -1;
204 char *debug_filename = debug_link->c_data;
205 int offset = (strlen(debug_filename) + 4) >> 2;
206 static unsigned int crc;
207 crc = ((unsigned int*)debug_link->c_data)[offset];
208 char *debug_pathname = malloc(strlen(debug_filename)
209 + strlen(name)
210 + strlen(".debug/")
211 + strlen(debug_file_directory)
212 + 2);
213 strcpy(debug_pathname, name);
214 char *last_slash = strrchr(debug_pathname, '/');
215 if (last_slash == NULL) {
216 free(debug_pathname);
217 return -1;
218 }
219
220 /* Look in the same directory as the object. */
221 strcpy(last_slash+1, debug_filename);
222 debug_fd = open_debug_file(debug_pathname, crc);
223 if (debug_fd >= 0) {
224 free(debug_pathname);
225 return debug_fd;
226 }
227
228 /* Look in a subdirectory named ".debug". */
229 strcpy(last_slash+1, ".debug/");
230 strcat(last_slash, debug_filename);
231
232 debug_fd = open_debug_file(debug_pathname, crc);
233 if (debug_fd >= 0) {
234 free(debug_pathname);
235 return debug_fd;
236 }
237
238 /* Look in /usr/lib/debug + the full pathname. */
239 strcpy(debug_pathname, debug_file_directory);
240 strcat(debug_pathname, name);
241 last_slash = strrchr(debug_pathname, '/');
242 strcpy(last_slash+1, debug_filename);
243
244 debug_fd = open_debug_file(debug_pathname, crc);
245 if (debug_fd >= 0) {
246 free(debug_pathname);
247 return debug_fd;
248 }
249
250 free(debug_pathname);
251 return -1;
252}
253
254static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo);
255
256/* Look for a ".gnu_debuglink" section. If one exists, try to open a
257 suitable debuginfo file and read a symbol table from it. */
258static struct symtab *build_symtab_from_debug_link(const char *name,
259 int fd,
260 ELF_EHDR *ehdr,
261 struct elf_section *scn_cache)
262{
263 fd = open_file_from_debug_link(name, fd, ehdr, scn_cache);
264
265 if (fd >= 0) {
266 struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
267 close(fd);
268 return symtab;
269 }
270
271 return NULL;
272}
273
274// Given a build_id, find the associated debuginfo file
275static char *
276build_id_to_debug_filename (size_t size, unsigned char *data)
277{
278 char *filename, *s;
279
280 filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1
281 + 2 * size + (sizeof ".debug" - 1) + 1);
282 s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory);
283 if (size > 0)
284 {
285 size--;
286 s += sprintf (s, "%02x", *data++);
287 }
288 if (size > 0)
289 *s++ = '/';
290 while (size-- > 0)
291 s += sprintf (s, "%02x", *data++);
292 strcpy (s, ".debug");
293
294 return filename;
295}
296
297// Read a build ID note. Try to open any associated debuginfo file
298// and return its symtab
299static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note)
300{
301 int fd;
302 struct symtab *symtab = NULL;
303
304 unsigned char *bytes
305 = (unsigned char*)(note+1) + note->n_namesz;
306 char *filename
307 = (build_id_to_debug_filename (note->n_descsz, bytes));
308
309 fd = pathmap_open(filename);
310 if (fd >= 0) {
311 symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
312 close(fd);
313 }
314 free(filename);
315
316 return symtab;
317}
318
319// read symbol table from given fd. If try_debuginfo) is true, also
320// try to open an associated debuginfo file
321static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) {
322 ELF_EHDR ehdr;
323 char *names = NULL;
324 struct symtab* symtab = NULL;
325
326 // Reading of elf header
327 struct elf_section *scn_cache = NULL;
328#if defined(ppc64) && !defined(ABI_ELFv2)
329 // Only big endian ppc64 (i.e. ABI_ELFv1) has 'official procedure descriptors' in ELF files
330 // see: http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html
331 struct elf_section *opd_sect = NULL;
332 ELF_SHDR *opd = NULL;
333#endif
334 int cnt = 0;
335 ELF_SHDR* shbuf = NULL;
336 ELF_SHDR* cursct = NULL;
337 ELF_PHDR* phbuf = NULL;
338 ELF_PHDR* phdr = NULL;
339 int sym_section = SHT_DYNSYM;
340
341 uintptr_t baseaddr = (uintptr_t)-1;
342
343 lseek(fd, (off_t)0L, SEEK_SET);
344 if (! read_elf_header(fd, &ehdr)) {
345 // not an elf
346 return NULL;
347 }
348
349 // read ELF header
350 if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {
351 goto quit;
352 }
353
354 baseaddr = find_base_address(fd, &ehdr);
355
356 scn_cache = (struct elf_section *)
357 calloc(ehdr.e_shnum * sizeof(struct elf_section), 1);
358 if (scn_cache == NULL) {
359 goto quit;
360 }
361
362 for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
363 scn_cache[cnt].c_shdr = cursct;
364 if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB
365 || cursct->sh_type == SHT_NOTE || cursct->sh_type == SHT_DYNSYM) {
366 if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
367 goto quit;
368 }
369 }
370 if (cursct->sh_type == SHT_SYMTAB) {
371 // Full symbol table available so use that
372 sym_section = cursct->sh_type;
373 }
374 cursct++;
375 }
376
377#if defined(ppc64) && !defined(ABI_ELFv2)
378 opd_sect = find_section_by_name(".opd", fd, &ehdr, scn_cache);
379 if (opd_sect != NULL && opd_sect->c_data != NULL && opd_sect->c_shdr != NULL) {
380 // plausibility check
381 opd = opd_sect->c_shdr;
382 }
383#endif
384
385 for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
386 ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
387
388 if (shdr->sh_type == sym_section) {
389 ELF_SYM *syms;
390 int rslt;
391 size_t size, n, j, htab_sz;
392
393 // FIXME: there could be multiple data buffers associated with the
394 // same ELF section. Here we can handle only one buffer. See man page
395 // for elf_getdata on Solaris.
396
397 // guarantee(symtab == NULL, "multiple symtab");
398 symtab = (struct symtab*)calloc(1, sizeof(struct symtab));
399 if (symtab == NULL) {
400 goto quit;
401 }
402 // the symbol table
403 syms = (ELF_SYM *)scn_cache[cnt].c_data;
404
405 // number of symbols
406 n = shdr->sh_size / shdr->sh_entsize;
407
408 // create hash table, we use hcreate_r, hsearch_r and hdestroy_r to
409 // manipulate the hash table.
410
411 // NOTES section in the man page of hcreate_r says
412 // "Hash table implementations are usually more efficient when
413 // the table contains enough free space to minimize collisions.
414 // Typically, this means that nel should be at least 25% larger
415 // than the maximum number of elements that the caller expects
416 // to store in the table."
417 htab_sz = n*1.25;
418
419 symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data));
420 rslt = hcreate_r(n, symtab->hash_table);
421 // guarantee(rslt, "unexpected failure: hcreate_r");
422
423 // shdr->sh_link points to the section that contains the actual strings
424 // for symbol names. the st_name field in ELF_SYM is just the
425 // string table index. we make a copy of the string table so the
426 // strings will not be destroyed by elf_end.
427 size = scn_cache[shdr->sh_link].c_shdr->sh_size;
428 symtab->strs = (char *)malloc(size);
429 memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
430
431 // allocate memory for storing symbol offset and size;
432 symtab->num_symbols = n;
433 symtab->symbols = (struct elf_symbol *)calloc(n , sizeof(struct elf_symbol));
434
435 // copy symbols info our symtab and enter them info the hash table
436 for (j = 0; j < n; j++, syms++) {
437 ENTRY item, *ret;
438 uintptr_t sym_value;
439 char *sym_name = symtab->strs + syms->st_name;
440
441 // skip non-object and non-function symbols
442 int st_type = ELF_ST_TYPE(syms->st_info);
443 if ( st_type != STT_FUNC && st_type != STT_OBJECT)
444 continue;
445 // skip empty strings and undefined symbols
446 if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
447
448 symtab->symbols[j].name = sym_name;
449 symtab->symbols[j].size = syms->st_size;
450 sym_value = syms->st_value;
451
452#if defined(ppc64) && !defined(ABI_ELFv2)
453 // see hotspot/src/share/vm/utilities/elfFuncDescTable.hpp for a detailed description
454 // of why we have to go this extra way via the '.opd' section on big endian ppc64
455 if (opd != NULL && *sym_name != '.' &&
456 (opd->sh_addr <= sym_value && sym_value <= opd->sh_addr + opd->sh_size)) {
457 sym_value = ((ELF_ADDR*)opd_sect->c_data)[(sym_value - opd->sh_addr) / sizeof(ELF_ADDR*)];
458 }
459#endif
460
461 symtab->symbols[j].offset = sym_value - baseaddr;
462 item.key = sym_name;
463 item.data = (void *)&(symtab->symbols[j]);
464 hsearch_r(item, ENTER, &ret, symtab->hash_table);
465 }
466 }
467 }
468
469#if defined(ppc64) && !defined(ABI_ELFv2)
470 // On Linux/PPC64 the debuginfo files contain an empty function descriptor
471 // section (i.e. '.opd' section) which makes the resolution of symbols
472 // with the above algorithm impossible (we would need the have both, the
473 // .opd section from the library and the symbol table from the debuginfo
474 // file which doesn't match with the current workflow.)
475 goto quit;
476#endif
477
478 // Look for a separate debuginfo file.
479 if (try_debuginfo) {
480 // We prefer a debug symtab to an object's own symtab, so look in
481 // the debuginfo file. We stash a copy of the old symtab in case
482 // there is no debuginfo.
483 struct symtab* prev_symtab = symtab;
484 symtab = NULL;
485
486#ifdef NT_GNU_BUILD_ID
487 // First we look for a Build ID
488 for (cursct = shbuf, cnt = 0;
489 symtab == NULL && cnt < ehdr.e_shnum;
490 cnt++) {
491 if (cursct->sh_type == SHT_NOTE) {
492 Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data;
493 if (note->n_type == NT_GNU_BUILD_ID) {
494 symtab = build_symtab_from_build_id(note);
495 }
496 }
497 cursct++;
498 }
499#endif
500
501 // Then, if that doesn't work, the debug link
502 if (symtab == NULL) {
503 symtab = build_symtab_from_debug_link(filename, fd, &ehdr,
504 scn_cache);
505 }
506
507 // If we still haven't found a symtab, use the object's own symtab.
508 if (symtab != NULL) {
509 if (prev_symtab != NULL)
510 destroy_symtab(prev_symtab);
511 } else {
512 symtab = prev_symtab;
513 }
514 }
515
516quit:
517 if (shbuf) free(shbuf);
518 if (phbuf) free(phbuf);
519 if (scn_cache) {
520 for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {
521 if (scn_cache[cnt].c_data != NULL) {
522 free(scn_cache[cnt].c_data);
523 }
524 }
525 free(scn_cache);
526 }
527 return symtab;
528}
529
530struct symtab* build_symtab(int fd, const char *filename) {
531 return build_symtab_internal(fd, filename, /* try_debuginfo */ true);
532}
533
534
535void destroy_symtab(struct symtab* symtab) {
536 if (!symtab) return;
537 if (symtab->strs) free(symtab->strs);
538 if (symtab->symbols) free(symtab->symbols);
539 if (symtab->hash_table) {
540 hdestroy_r(symtab->hash_table);
541 free(symtab->hash_table);
542 }
543 free(symtab);
544}
545
546uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
547 const char *sym_name, int *sym_size) {
548 ENTRY item;
549 ENTRY* ret = NULL;
550
551 // library does not have symbol table
552 if (!symtab || !symtab->hash_table)
553 return (uintptr_t)NULL;
554
555 item.key = (char*) strdup(sym_name);
556 item.data = NULL;
557 hsearch_r(item, FIND, &ret, symtab->hash_table);
558 if (ret) {
559 struct elf_symbol * sym = (struct elf_symbol *)(ret->data);
560 uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
561 if (sym_size) *sym_size = sym->size;
562 free(item.key);
563 return rslt;
564 }
565
566quit:
567 free(item.key);
568 return (uintptr_t) NULL;
569}
570
571const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
572 uintptr_t* poffset) {
573 int n = 0;
574 if (!symtab) return NULL;
575 for (; n < symtab->num_symbols; n++) {
576 struct elf_symbol* sym = &(symtab->symbols[n]);
577 if (sym->name != NULL &&
578 offset >= sym->offset && offset < sym->offset + sym->size) {
579 if (poffset) *poffset = (offset - sym->offset);
580 return sym->name;
581 }
582 }
583 return NULL;
584}
585