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