1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/isa_defs.h>
27 #include <sys/link.h>
28 #include <strings.h>
29 #include <stdlib.h>
30
31 #include <mdb/mdb_debug.h>
32 #include <mdb/mdb_modapi.h>
33 #include <mdb/mdb_io_impl.h>
34 #include <mdb/mdb_gelf.h>
35 #include <mdb/mdb_err.h>
36 #include <mdb/mdb.h>
37
38 #define GST_GROW 2 /* Mutable symbol table growth multiplier */
39 #define GST_DEFSZ 16 /* Mutable symbol table initial size */
40
41 #define GST_NVFLG (MDB_NV_EXTNAME | MDB_NV_SILENT)
42
43 static const char *gelf_strtab; /* Active string table for qsort callbacks */
44
45 static mdb_gelf_file_t *
gelf_sect_init(mdb_gelf_file_t * gf)46 gelf_sect_init(mdb_gelf_file_t *gf)
47 {
48 mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_shstrndx];
49 size_t i;
50 GElf_Half npbit = 0;
51 GElf_Shdr *shp;
52 GElf_Phdr *gpp;
53
54 if (gf->gf_mode == GF_PROGRAM)
55 gf->gf_shnum = 0; /* Simplifies other code paths */
56
57 if (gf->gf_shnum == 0)
58 return (gf); /* If no section headers we're done here */
59
60 if (IOP_SEEK(gf->gf_io, shstr->gs_shdr.sh_offset, SEEK_SET) == -1) {
61 warn("failed to seek %s to shdr strings", IOP_NAME(gf->gf_io));
62 return (NULL);
63 }
64
65 shstr->gs_data = mdb_zalloc(shstr->gs_shdr.sh_size + 1, UM_SLEEP);
66
67 if (IOP_READ(gf->gf_io, shstr->gs_data, shstr->gs_shdr.sh_size) !=
68 shstr->gs_shdr.sh_size) {
69 warn("failed to read %s shdr strings", IOP_NAME(gf->gf_io));
70 mdb_free(shstr->gs_data, shstr->gs_shdr.sh_size);
71 return (NULL);
72 }
73
74 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
75 shp = &gsp->gs_shdr;
76 gsp->gs_name = (const char *)shstr->gs_data + shp->sh_name;
77
78 if (shp->sh_name >= shstr->gs_shdr.sh_size) {
79 warn("section name for %s:[%u] is corrupt: %u\n",
80 IOP_NAME(gf->gf_io), i, shp->sh_name);
81 gsp->gs_name = shstr->gs_data; /* empty string */
82 }
83
84 if (shp->sh_type == SHT_PROGBITS && (shp->sh_flags & SHF_ALLOC))
85 npbit++; /* Keep count for ET_REL code below */
86 }
87
88 /*
89 * If the file is of type ET_REL, we would still like to provide file
90 * i/o using the mdb_gelf_rw() function defined below. To simplify
91 * things, we forge up a sequence of Phdrs based on Shdrs which have
92 * been marked SHF_ALLOC and are of type SHT_PROGBITS. We convert
93 * relevant Shdr fields to their Phdr equivalents, and then set the
94 * p_vaddr (virtual base address) to the section's file offset.
95 * This allows us to relocate a given symbol by simply incrementing
96 * its st_value by the file offset of the section corresponding to
97 * its st_shndx, and then perform i/o to read or write the symbol's
98 * value in the object file.
99 */
100 if (gf->gf_ehdr.e_type == ET_REL && npbit != 0) {
101 gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * npbit, UM_SLEEP);
102 gf->gf_phnum = npbit;
103 gf->gf_npload = npbit;
104
105 gpp = gf->gf_phdrs;
106 gsp = gf->gf_sects;
107
108 for (i = 0; i < gf->gf_shnum; i++, gsp++) {
109 shp = &gsp->gs_shdr;
110
111 if ((shp->sh_type == SHT_PROGBITS) &&
112 (shp->sh_flags & SHF_ALLOC)) {
113 gpp->p_type = PT_LOAD;
114 gpp->p_flags = PF_R;
115
116 if (shp->sh_flags & SHF_EXECINSTR)
117 gpp->p_flags |= PF_X;
118 if (shp->sh_flags & SHF_WRITE)
119 gpp->p_flags |= PF_W;
120
121 gpp->p_offset = shp->sh_offset;
122 gpp->p_vaddr = shp->sh_offset;
123 gpp->p_filesz = shp->sh_size;
124 gpp->p_memsz = shp->sh_size;
125 gpp->p_align = shp->sh_addralign;
126
127 gpp++;
128 }
129 }
130 }
131
132 return (gf);
133 }
134
135 void *
mdb_gelf_sect_load(mdb_gelf_file_t * gf,mdb_gelf_sect_t * gsp)136 mdb_gelf_sect_load(mdb_gelf_file_t *gf, mdb_gelf_sect_t *gsp)
137 {
138 ssize_t nbytes;
139
140 if (gsp->gs_data != NULL)
141 return (gsp->gs_data);
142
143 mdb_dprintf(MDB_DBG_ELF, "loading %s:%s (%lu bytes)\n",
144 IOP_NAME(gf->gf_io), gsp->gs_name, (ulong_t)gsp->gs_shdr.sh_size);
145
146 gsp->gs_data = mdb_alloc(gsp->gs_shdr.sh_size, UM_SLEEP);
147
148 if (IOP_SEEK(gf->gf_io, gsp->gs_shdr.sh_offset, SEEK_SET) == -1) {
149 warn("failed to seek to start of %s:%s",
150 IOP_NAME(gf->gf_io), gsp->gs_name);
151 goto err;
152 }
153
154 nbytes = IOP_READ(gf->gf_io, gsp->gs_data, gsp->gs_shdr.sh_size);
155
156 if (nbytes < 0) {
157 warn("failed to read %s:%s", IOP_NAME(gf->gf_io), gsp->gs_name);
158 goto err;
159 }
160
161 if (nbytes < gsp->gs_shdr.sh_size) {
162 mdb_dprintf(MDB_DBG_ELF, "only %ld of %llu bytes of %s:%s "
163 "could be read\n", (long)nbytes, (u_longlong_t)
164 gsp->gs_shdr.sh_size, IOP_NAME(gf->gf_io), gsp->gs_name);
165 bzero((char *)gsp->gs_data + nbytes,
166 (size_t)gsp->gs_shdr.sh_size - nbytes);
167 }
168
169 return (gsp->gs_data);
170
171 err:
172 mdb_free(gsp->gs_data, sizeof (gsp->gs_shdr.sh_size));
173 gsp->gs_data = NULL;
174 return (NULL);
175 }
176
177 void
mdb_gelf_ehdr_to_gehdr(Ehdr * src,GElf_Ehdr * dst)178 mdb_gelf_ehdr_to_gehdr(Ehdr *src, GElf_Ehdr *dst)
179 {
180 bcopy(src->e_ident, dst->e_ident, sizeof (dst->e_ident));
181 dst->e_type = src->e_type;
182 dst->e_machine = src->e_machine;
183 dst->e_version = src->e_version;
184 dst->e_entry = src->e_entry;
185 dst->e_phoff = src->e_phoff;
186 dst->e_shoff = src->e_shoff;
187 dst->e_flags = src->e_flags;
188 dst->e_ehsize = src->e_ehsize;
189 dst->e_phentsize = src->e_phentsize;
190 dst->e_phnum = src->e_phnum;
191 dst->e_shentsize = src->e_shentsize;
192 dst->e_shnum = src->e_shnum;
193 dst->e_shstrndx = src->e_shstrndx;
194 }
195
196 static GElf_Shdr *
gelf32_to_shdr(const Elf32_Shdr * src,GElf_Shdr * dst)197 gelf32_to_shdr(const Elf32_Shdr *src, GElf_Shdr *dst)
198 {
199 if (src != NULL) {
200 dst->sh_name = src->sh_name;
201 dst->sh_type = src->sh_type;
202 dst->sh_flags = src->sh_flags;
203 dst->sh_addr = src->sh_addr;
204 dst->sh_offset = src->sh_offset;
205 dst->sh_size = src->sh_size;
206 dst->sh_link = src->sh_link;
207 dst->sh_info = src->sh_info;
208 dst->sh_addralign = src->sh_addralign;
209 dst->sh_entsize = src->sh_entsize;
210
211 return (dst);
212 }
213
214 return (NULL);
215 }
216
217 static GElf_Shdr *
gelf64_to_shdr(const Elf64_Shdr * src,GElf_Shdr * dst)218 gelf64_to_shdr(const Elf64_Shdr *src, GElf_Shdr *dst)
219 {
220 if (src != NULL) {
221 bcopy(src, dst, sizeof (Elf64_Shdr));
222 return (dst);
223 }
224
225 return (NULL);
226 }
227
228 static mdb_gelf_file_t *
gelf_shdrs_init(mdb_gelf_file_t * gf,size_t shdr_size,GElf_Shdr * (* elf2gelf)(const void *,GElf_Shdr *))229 gelf_shdrs_init(mdb_gelf_file_t *gf, size_t shdr_size,
230 GElf_Shdr *(*elf2gelf)(const void *, GElf_Shdr *))
231 {
232 caddr_t shdrs, shp;
233 size_t i;
234
235 mdb_gelf_sect_t *gsp;
236 size_t nbytes;
237
238 mdb_dprintf(MDB_DBG_ELF, "loading %s section headers (%u entries)\n",
239 IOP_NAME(gf->gf_io), gf->gf_shnum);
240
241 if (gf->gf_shnum == 0)
242 return (gf);
243
244 if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_shoff, SEEK_SET) == -1) {
245 warn("failed to seek %s to shdrs", IOP_NAME(gf->gf_io));
246 return (NULL);
247 }
248
249 nbytes = shdr_size * gf->gf_shnum;
250 shdrs = mdb_alloc(nbytes, UM_SLEEP);
251
252 if (IOP_READ(gf->gf_io, shdrs, nbytes) != nbytes) {
253 warn("failed to read %s section headers", IOP_NAME(gf->gf_io));
254 mdb_free(shdrs, nbytes);
255 return (NULL);
256 }
257
258 gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) * gf->gf_shnum,
259 UM_SLEEP);
260
261 shp = shdrs;
262 gsp = gf->gf_sects;
263
264 for (i = 0; i < gf->gf_shnum; i++, shp += shdr_size, gsp++)
265 (void) elf2gelf(shp, &gsp->gs_shdr);
266
267 mdb_free(shdrs, nbytes);
268 return (gf);
269 }
270
271 static GElf_Phdr *
gelf32_to_phdr(const Elf32_Phdr * src,GElf_Phdr * dst)272 gelf32_to_phdr(const Elf32_Phdr *src, GElf_Phdr *dst)
273 {
274 if (src != NULL) {
275 dst->p_type = src->p_type;
276 dst->p_offset = src->p_offset;
277 dst->p_vaddr = src->p_vaddr;
278 dst->p_paddr = src->p_paddr;
279 dst->p_filesz = src->p_filesz;
280 dst->p_memsz = src->p_memsz;
281 dst->p_flags = src->p_flags;
282 dst->p_align = src->p_align;
283
284 return (dst);
285 }
286
287 return (NULL);
288 }
289
290 static GElf_Phdr *
gelf64_to_phdr(const Elf64_Phdr * src,GElf_Phdr * dst)291 gelf64_to_phdr(const Elf64_Phdr *src, GElf_Phdr *dst)
292 {
293 if (src != NULL) {
294 bcopy(src, dst, sizeof (Elf64_Phdr));
295 return (dst);
296 }
297
298 return (NULL);
299 }
300
301 static int
gelf_phdr_compare(const void * lp,const void * rp)302 gelf_phdr_compare(const void *lp, const void *rp)
303 {
304 GElf_Phdr *lhs = (GElf_Phdr *)lp;
305 GElf_Phdr *rhs = (GElf_Phdr *)rp;
306
307 /*
308 * If both p_type fields are PT_LOAD, we want to sort by vaddr.
309 * Exception is that p_vaddr == 0 means ignore this (put at end).
310 */
311 if (lhs->p_type == PT_LOAD && rhs->p_type == PT_LOAD) {
312 if (lhs->p_vaddr != rhs->p_vaddr) {
313 if (lhs->p_vaddr == 0)
314 return (1); /* lhs is "greater" */
315
316 if (rhs->p_vaddr == 0)
317 return (-1); /* rhs is "greater" */
318
319 return (lhs->p_vaddr > rhs->p_vaddr ? 1 : -1);
320 }
321
322 return (0);
323 }
324
325 /*
326 * If the p_type fields don't match, we need to make sure that PT_LOAD
327 * entries are considered "less" (i.e. move towards the beginning
328 * of the array we are sorting)
329 */
330 if (lhs->p_type != rhs->p_type) {
331 if (lhs->p_type == PT_LOAD)
332 return (-1); /* rhs is "greater" */
333
334 if (rhs->p_type == PT_LOAD)
335 return (1); /* lhs is "greater" */
336
337 return (lhs->p_type > rhs->p_type ? 1 : -1);
338 }
339
340 /*
341 * If the p_type is the same but neither is PT_LOAD, then
342 * just sort by file offset (doesn't really matter)
343 */
344 if (lhs->p_offset != rhs->p_offset)
345 return (lhs->p_offset > rhs->p_offset ? 1 : -1);
346
347 return (0);
348 }
349
350 static mdb_gelf_file_t *
gelf_phdrs_init(mdb_gelf_file_t * gf,size_t phdr_size,GElf_Phdr * (* elf2gelf)(const void *,GElf_Phdr *))351 gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
352 GElf_Phdr *(*elf2gelf)(const void *, GElf_Phdr *))
353 {
354 caddr_t phdrs, php;
355 size_t i;
356
357 GElf_Phdr *gpp;
358 size_t nbytes;
359
360 mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%lu entries)\n",
361 IOP_NAME(gf->gf_io), gf->gf_phnum);
362
363 if (gf->gf_phnum == 0)
364 return (gf);
365
366 if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_phoff, SEEK_SET) == -1) {
367 warn("failed to seek %s to phdrs", IOP_NAME(gf->gf_io));
368 return (NULL);
369 }
370
371 nbytes = phdr_size * gf->gf_phnum;
372 phdrs = mdb_alloc(nbytes, UM_SLEEP);
373
374 if (IOP_READ(gf->gf_io, phdrs, nbytes) != nbytes) {
375 warn("failed to read %s program headers", IOP_NAME(gf->gf_io));
376 mdb_free(phdrs, nbytes);
377 return (NULL);
378 }
379
380 gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * gf->gf_phnum, UM_SLEEP);
381
382 php = phdrs;
383 gpp = gf->gf_phdrs;
384
385 /*
386 * Iterate through the list of phdrs locating those that are of type
387 * PT_LOAD; increment gf_npload so we know how many are loadable.
388 */
389 for (i = 0; i < gf->gf_phnum; i++, php += phdr_size, gpp++) {
390 (void) elf2gelf(php, gpp);
391 if (gpp->p_type != PT_LOAD)
392 continue;
393
394 mdb_dprintf(MDB_DBG_ELF, "PT_LOAD va=0x%llx flags=0x%x "
395 "memsz=%llu filesz=%llu off=%llu\n", (u_longlong_t)
396 gpp->p_vaddr, gpp->p_flags, (u_longlong_t)gpp->p_memsz,
397 (u_longlong_t)gpp->p_filesz, (u_longlong_t)gpp->p_offset);
398
399 gf->gf_npload++;
400 }
401
402 /*
403 * Now we sort the phdrs array using a comparison routine which
404 * arranges for the PT_LOAD phdrs with non-zero virtual addresses
405 * to come first sorted by virtual address. This means that we
406 * can access the complete phdr table by examining the array
407 * gf->gf_phdrs[0 .. gf->gf_phnum - 1], and we can access a sorted
408 * array of valid PT_LOAD pdhrs by examining the array
409 * gf->gf_phdrs[0 .. gf->gf_npload - 1].
410 */
411 qsort(gf->gf_phdrs, gf->gf_phnum, sizeof (GElf_Phdr),
412 gelf_phdr_compare);
413
414 /*
415 * Locate the PT_DYNAMIC Phdr if one is present; we save this
416 * Phdr pointer in gf->gf_dynp for future use.
417 */
418 for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_phnum; i++, gpp++) {
419 if (gpp->p_type == PT_DYNAMIC) {
420 mdb_dprintf(MDB_DBG_ELF, "PT_DYNAMIC "
421 "filesize = %lluULL off=%lluULL\n",
422 (u_longlong_t)gpp->p_filesz,
423 (u_longlong_t)gpp->p_offset);
424
425 gf->gf_dynp = gpp;
426 break;
427 }
428 }
429
430 mdb_free(phdrs, nbytes);
431 return (gf);
432 }
433
434 static GElf_Dyn *
gelf32_to_dyn(const Elf32_Dyn * src,GElf_Dyn * dst)435 gelf32_to_dyn(const Elf32_Dyn *src, GElf_Dyn *dst)
436 {
437 if (src != NULL) {
438 dst->d_tag = (GElf_Xword)(Elf32_Word)src->d_tag;
439 dst->d_un.d_ptr = src->d_un.d_ptr;
440 return (dst);
441 }
442
443 return (NULL);
444 }
445
446 static GElf_Dyn *
gelf64_to_dyn(const Elf64_Dyn * src,GElf_Dyn * dst)447 gelf64_to_dyn(const Elf64_Dyn *src, GElf_Dyn *dst)
448 {
449 if (src != NULL) {
450 bcopy(src, dst, sizeof (Elf64_Dyn));
451 return (dst);
452 }
453
454 return (NULL);
455 }
456
457 static GElf_Xword
gelf_dyn_lookup(mdb_gelf_file_t * gf,GElf_Xword tag)458 gelf_dyn_lookup(mdb_gelf_file_t *gf, GElf_Xword tag)
459 {
460 size_t i;
461
462 for (i = 0; i < gf->gf_ndyns; i++) {
463 if (gf->gf_dyns[i].d_tag == tag)
464 return (gf->gf_dyns[i].d_un.d_val);
465 }
466
467 return ((GElf_Xword)-1L);
468 }
469
470 void
mdb_gelf_dyns_set(mdb_gelf_file_t * gf,void * dyns,size_t dyns_sz)471 mdb_gelf_dyns_set(mdb_gelf_file_t *gf, void *dyns, size_t dyns_sz)
472 {
473 size_t ndyns, i, dyn_size;
474 caddr_t dp;
475 GElf_Dyn *gdp;
476
477 if (gf->gf_dyns != NULL) {
478 /* Free the existing dyn entries */
479 free(gf->gf_dyns);
480 gf->gf_dyns = NULL;
481 gf->gf_ndyns = 0;
482 }
483
484 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32)
485 dyn_size = sizeof (Elf32_Dyn);
486 else
487 dyn_size = sizeof (Elf64_Dyn);
488
489 ndyns = dyns_sz / dyn_size;
490 gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP);
491 gf->gf_ndyns = ndyns;
492
493 dp = dyns;
494 gdp = gf->gf_dyns;
495
496 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
497 for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) {
498 /* LINTED - alignment */
499 (void) gelf32_to_dyn((Elf32_Dyn *)dp, gdp);
500 }
501 } else {
502 for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) {
503 /* LINTED - alignment */
504 (void) gelf64_to_dyn((Elf64_Dyn *)dp, gdp);
505 }
506 }
507 }
508
509 static GElf_Dyn *
gelf_dyns_init(mdb_gelf_file_t * gf,size_t dyn_size,GElf_Dyn * (* elf2gelf)(const void *,GElf_Dyn *))510 gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size,
511 GElf_Dyn *(*elf2gelf)(const void *, GElf_Dyn *))
512 {
513 size_t nbytes, ndyns, i;
514 caddr_t dyns, dp;
515 GElf_Dyn *gdp;
516
517 off64_t dyn_addr;
518
519 if (gf->gf_dyns != NULL)
520 return (gf->gf_dyns); /* Already loaded */
521
522 if (gf->gf_dynp == NULL)
523 return (NULL); /* No PT_DYNAMIC entry was found */
524
525 nbytes = gf->gf_dynp->p_filesz;
526 ndyns = nbytes / dyn_size;
527
528 /*
529 * If this is an executable in PROGRAM view, then p_vaddr is an
530 * absolute address; we need to subtract the virtual base address of
531 * the mapping. In FILE view, dyn_addr is just the file offset.
532 */
533 if (gf->gf_mode == GF_PROGRAM) {
534 if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0)
535 dyn_addr = gf->gf_dynp->p_vaddr - gf->gf_phdrs->p_vaddr;
536 else
537 dyn_addr = gf->gf_dynp->p_vaddr;
538 } else {
539 mdb_gelf_sect_t *gsp = gf->gf_sects;
540
541 for (i = 0; i < gf->gf_shnum; i++, gsp++) {
542 if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) {
543 dyn_addr = gsp->gs_shdr.sh_offset;
544 break;
545 }
546 }
547
548 if (i == gf->gf_shnum)
549 return (NULL); /* No SHT_DYNAMIC entry was found */
550 }
551
552 mdb_dprintf(MDB_DBG_ELF, "loading _DYNAMIC[] (%lu entries) "
553 "from offset %llx\n", (ulong_t)ndyns, (longlong_t)dyn_addr);
554
555 if (IOP_SEEK(gf->gf_io, dyn_addr, SEEK_SET) == -1) {
556 warn("failed to seek %s to _DYNAMIC", IOP_NAME(gf->gf_io));
557 return (NULL);
558 }
559
560 dyns = mdb_alloc(nbytes, UM_SLEEP);
561
562 if (IOP_READ(gf->gf_io, dyns, nbytes) != nbytes) {
563 warn("failed to read %s:_DYNAMIC", IOP_NAME(gf->gf_io));
564 mdb_free(dyns, nbytes);
565 return (NULL);
566 }
567
568 gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP);
569 gf->gf_ndyns = ndyns;
570
571 dp = dyns;
572 gdp = gf->gf_dyns;
573
574 for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++)
575 (void) elf2gelf(dp, gdp);
576
577 mdb_free(dyns, nbytes);
578 return (gf->gf_dyns);
579 }
580
581 static mdb_gelf_file_t *
gelf32_init(mdb_gelf_file_t * gf,mdb_io_t * io,const Elf32_Ehdr * ehdr)582 gelf32_init(mdb_gelf_file_t *gf, mdb_io_t *io, const Elf32_Ehdr *ehdr)
583 {
584 /*
585 * Convert the Elf32_Ehdr to a GElf_Ehdr
586 */
587 bcopy(ehdr->e_ident, gf->gf_ehdr.e_ident, EI_NIDENT);
588
589 gf->gf_ehdr.e_type = ehdr->e_type;
590 gf->gf_ehdr.e_machine = ehdr->e_machine;
591 gf->gf_ehdr.e_version = ehdr->e_version;
592 gf->gf_ehdr.e_entry = ehdr->e_entry;
593 gf->gf_ehdr.e_phoff = ehdr->e_phoff;
594 gf->gf_ehdr.e_shoff = ehdr->e_shoff;
595 gf->gf_ehdr.e_flags = ehdr->e_flags;
596 gf->gf_ehdr.e_ehsize = ehdr->e_ehsize;
597 gf->gf_ehdr.e_phentsize = ehdr->e_phentsize;
598 gf->gf_ehdr.e_phnum = ehdr->e_phnum;
599 gf->gf_ehdr.e_shentsize = ehdr->e_shentsize;
600 gf->gf_ehdr.e_shnum = ehdr->e_shnum;
601 gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx;
602
603 gf->gf_shnum = gf->gf_ehdr.e_shnum;
604 gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
605 gf->gf_phnum = gf->gf_ehdr.e_phnum;
606
607 if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
608 gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
609 Elf32_Shdr shdr0;
610
611 if (ehdr->e_shoff == 0)
612 return (NULL);
613
614 if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
615 warn("failed to seek %s", IOP_NAME(io));
616 return (NULL);
617 }
618
619 if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
620 warn("failed to read extended ELF header from %s",
621 IOP_NAME(io));
622 return (NULL);
623 }
624
625 if (gf->gf_shnum == 0)
626 gf->gf_shnum = shdr0.sh_size;
627
628 if (gf->gf_shstrndx == SHN_XINDEX)
629 gf->gf_shstrndx = shdr0.sh_link;
630
631 if (gf->gf_phnum == PN_XNUM)
632 gf->gf_phnum = shdr0.sh_info;
633 }
634
635 /*
636 * Initialize the section and program headers. We skip initializing
637 * the section headers if this is a program image because they are
638 * not loadable and thus we can't get at them.
639 */
640 if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf32_Shdr),
641 (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf32_to_shdr) == NULL)
642 return (NULL);
643
644 if (gelf_phdrs_init(gf, sizeof (Elf32_Phdr),
645 (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf32_to_phdr) == NULL)
646 return (NULL);
647
648 (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn),
649 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn);
650
651 return (gf);
652 }
653
654 static mdb_gelf_file_t *
gelf64_init(mdb_gelf_file_t * gf,mdb_io_t * io,Elf64_Ehdr * ehdr)655 gelf64_init(mdb_gelf_file_t *gf, mdb_io_t *io, Elf64_Ehdr *ehdr)
656 {
657 /*
658 * Save a copy of the ELF file header
659 */
660 bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr));
661
662 gf->gf_shnum = gf->gf_ehdr.e_shnum;
663 gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
664 gf->gf_phnum = gf->gf_ehdr.e_phnum;
665
666 if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
667 gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
668 Elf64_Shdr shdr0;
669
670 if (ehdr->e_shoff == 0)
671 return (NULL);
672
673 if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
674 warn("failed to seek %s", IOP_NAME(io));
675 return (NULL);
676 }
677
678 if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
679 warn("failed to read extended ELF header from %s",
680 IOP_NAME(io));
681 return (NULL);
682 }
683
684 if (gf->gf_shnum == 0)
685 gf->gf_shnum = shdr0.sh_size;
686
687 if (gf->gf_shstrndx == SHN_XINDEX)
688 gf->gf_shstrndx = shdr0.sh_link;
689
690 if (gf->gf_phnum == PN_XNUM)
691 gf->gf_phnum = shdr0.sh_info;
692 }
693
694 /*
695 * Initialize the section and program headers. We skip initializing
696 * the section headers if this is a program image because they are
697 * not loadable and thus we can't get at them.
698 */
699 if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf64_Shdr),
700 (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf64_to_shdr) == NULL)
701 return (NULL);
702
703 if (gelf_phdrs_init(gf, sizeof (Elf64_Phdr),
704 (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf64_to_phdr) == NULL)
705 return (NULL);
706
707 (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn),
708 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn);
709
710 return (gf);
711 }
712
713 int
mdb_gelf_check(mdb_io_t * io,Elf32_Ehdr * ehp,GElf_Half etype)714 mdb_gelf_check(mdb_io_t *io, Elf32_Ehdr *ehp, GElf_Half etype)
715 {
716 #ifdef _BIG_ENDIAN
717 uchar_t order = ELFDATA2MSB;
718 #else
719 uchar_t order = ELFDATA2LSB;
720 #endif
721 ssize_t nbytes;
722
723 (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET);
724 nbytes = IOP_READ(io, ehp, sizeof (Elf32_Ehdr));
725
726 if (nbytes == -1) {
727 if (etype != ET_NONE)
728 warn("failed to read ELF header from %s", IOP_NAME(io));
729 return (-1);
730 }
731
732 if (nbytes != sizeof (Elf32_Ehdr) ||
733 bcmp(&ehp->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) {
734 if (etype != ET_NONE)
735 warn("%s is not an ELF file\n", IOP_NAME(io));
736 return (-1);
737 }
738
739 if (ehp->e_ident[EI_DATA] != order) {
740 warn("ELF file %s has different endianness from debugger\n",
741 IOP_NAME(io));
742 return (-1);
743 }
744
745 if (ehp->e_version != EV_CURRENT) {
746 warn("ELF file %s uses different ELF version (%lu) than "
747 "debugger (%u)\n", IOP_NAME(io),
748 (ulong_t)ehp->e_version, EV_CURRENT);
749 return (-1);
750 }
751
752 if (etype != ET_NONE && ehp->e_type != etype) {
753 warn("ELF file %s is not of the expected type\n", IOP_NAME(io));
754 return (-1);
755 }
756
757 return (0);
758 }
759
760 mdb_gelf_file_t *
mdb_gelf_create(mdb_io_t * io,GElf_Half etype,int mode)761 mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode)
762 {
763 union {
764 Elf32_Ehdr h32;
765 Elf64_Ehdr h64;
766 } ehdr;
767
768 mdb_gelf_file_t *gf = mdb_zalloc(sizeof (mdb_gelf_file_t), UM_SLEEP);
769
770 ASSERT(mode == GF_FILE || mode == GF_PROGRAM);
771 gf->gf_mode = mode;
772
773 /*
774 * Assign the i/o backend now, but don't hold it until we're sure
775 * we're going to succeed; otherwise the caller will be responsible
776 * for mdb_io_destroy()ing it.
777 */
778 gf->gf_io = io;
779
780 if (mdb_gelf_check(io, &ehdr.h32, etype) == -1)
781 goto err;
782
783 switch (ehdr.h32.e_ident[EI_CLASS]) {
784 case ELFCLASS32:
785 gf = gelf32_init(gf, io, &ehdr.h32);
786 break;
787
788 case ELFCLASS64:
789 if (IOP_SEEK(io, (off64_t)0L, SEEK_SET) == -1) {
790 warn("failed to seek %s", IOP_NAME(io));
791 goto err;
792 }
793
794 if (IOP_READ(io, &ehdr.h64, sizeof (ehdr.h64)) !=
795 sizeof (ehdr.h64)) {
796 warn("failed to read ELF header from %s", IOP_NAME(io));
797 goto err;
798 }
799
800 gf = gelf64_init(gf, io, &ehdr.h64);
801 break;
802
803 default:
804 warn("%s is an unsupported ELF class: %u\n",
805 IOP_NAME(io), ehdr.h32.e_ident[EI_CLASS]);
806 goto err;
807 }
808
809 if (gf != NULL && gelf_sect_init(gf) != NULL) {
810 gf->gf_io = mdb_io_hold(io);
811 return (gf);
812 }
813
814 err:
815 if (gf != NULL) {
816 if (gf->gf_sects != NULL) {
817 mdb_free(gf->gf_sects, gf->gf_shnum *
818 sizeof (mdb_gelf_sect_t));
819 }
820 mdb_free(gf, sizeof (mdb_gelf_file_t));
821 }
822 return (NULL);
823 }
824
825 void
mdb_gelf_destroy(mdb_gelf_file_t * gf)826 mdb_gelf_destroy(mdb_gelf_file_t *gf)
827 {
828 mdb_gelf_sect_t *gsp;
829 size_t i;
830
831 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
832 if (gsp->gs_data != NULL)
833 mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size);
834 }
835
836 mdb_free(gf->gf_sects,
837 gf->gf_shnum * sizeof (mdb_gelf_sect_t));
838
839 mdb_free(gf->gf_phdrs, gf->gf_phnum * sizeof (GElf_Phdr));
840
841 mdb_io_rele(gf->gf_io);
842 mdb_free(gf, sizeof (mdb_gelf_file_t));
843 }
844
845 /*
846 * Sort comparison function for 32-bit symbol address-to-name lookups. We sort
847 * symbols by value. If values are equal, we prefer the symbol that is
848 * non-zero sized, typed, not weak, or lexically first, in that order.
849 */
850 static int
gelf32_sym_compare(const void * lp,const void * rp)851 gelf32_sym_compare(const void *lp, const void *rp)
852 {
853 Elf32_Sym *lhs = *((Elf32_Sym **)lp);
854 Elf32_Sym *rhs = *((Elf32_Sym **)rp);
855
856 if (lhs->st_value != rhs->st_value)
857 return (lhs->st_value > rhs->st_value ? 1 : -1);
858
859 if ((lhs->st_size == 0) != (rhs->st_size == 0))
860 return (lhs->st_size == 0 ? 1 : -1);
861
862 if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
863 (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
864 return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
865
866 if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
867 (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
868 return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
869
870 return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name));
871 }
872
873 /*
874 * Sort comparison function for 64-bit symbol address-to-name lookups. We sort
875 * symbols by value. If values are equal, we prefer the symbol that is
876 * non-zero sized, typed, not weak, or lexically first, in that order.
877 */
878 static int
gelf64_sym_compare(const void * lp,const void * rp)879 gelf64_sym_compare(const void *lp, const void *rp)
880 {
881 Elf64_Sym *lhs = *((Elf64_Sym **)lp);
882 Elf64_Sym *rhs = *((Elf64_Sym **)rp);
883
884 if (lhs->st_value != rhs->st_value)
885 return (lhs->st_value > rhs->st_value ? 1 : -1);
886
887 if ((lhs->st_size == 0) != (rhs->st_size == 0))
888 return (lhs->st_size == 0 ? 1 : -1);
889
890 if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
891 (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
892 return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
893
894 if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
895 (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
896 return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
897
898 return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name));
899 }
900
901 static void
gelf32_symtab_sort(mdb_gelf_symtab_t * gst)902 gelf32_symtab_sort(mdb_gelf_symtab_t *gst)
903 {
904 Elf32_Sym **sympp = (Elf32_Sym **)gst->gst_asmap;
905 mdb_var_t *v;
906
907 mdb_nv_rewind(&gst->gst_nv);
908
909 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
910 Elf32_Sym *sym = MDB_NV_COOKIE(v);
911 if (sym->st_value != 0 &&
912 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
913 *sympp++ = sym;
914 }
915
916 gst->gst_aslen = (size_t)(sympp - (Elf32_Sym **)gst->gst_asmap);
917 ASSERT(gst->gst_aslen <= gst->gst_asrsv);
918
919 gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL;
920
921 qsort(gst->gst_asmap, gst->gst_aslen,
922 sizeof (Elf32_Sym *), gelf32_sym_compare);
923
924 gelf_strtab = NULL;
925 }
926
927 static void
gelf32_symtab_init(mdb_gelf_symtab_t * gst)928 gelf32_symtab_init(mdb_gelf_symtab_t *gst)
929 {
930 #if STT_NUM != (STT_TLS + 1)
931 #error "STT_NUM has grown. update gelf32_symtab_init()"
932 #endif
933
934 const char *base = (const char *)gst->gst_ssect->gs_data;
935 Elf32_Sym *sym = gst->gst_dsect->gs_data;
936 mdb_nv_t *nv = &gst->gst_nv;
937
938 Elf32_Word ss_size = gst->gst_ssect->gs_shdr.sh_size;
939 size_t asrsv = 0;
940 GElf_Word i, n;
941
942 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf32_Sym)) {
943 warn("%s sh_entsize %llu != sizeof (Elf32_Sym); "
944 "using %u instead\n", gst->gst_dsect->gs_name,
945 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize,
946 (uint_t)sizeof (Elf32_Sym));
947 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf32_Sym);
948 }
949
950 n = gst->gst_dsect->gs_shdr.sh_size /
951 gst->gst_dsect->gs_shdr.sh_entsize;
952
953 for (i = 0; i < n; i++, sym++) {
954 const char *name = base + sym->st_name;
955 uchar_t type = ELF32_ST_TYPE(sym->st_info);
956
957 if (type >= STT_NUM || type == STT_SECTION)
958 continue; /* skip sections and unknown types */
959
960 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') {
961 if (sym->st_name >= ss_size || name[0] != '\0') {
962 warn("ignoring %s symbol [%u]: invalid name\n",
963 gst->gst_dsect->gs_name, i);
964 sym->st_name = 0;
965 }
966 continue; /* skip corrupt or empty names */
967 }
968
969 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG);
970
971 if (sym->st_value != 0 &&
972 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
973 asrsv++; /* reserve space in the address map */
974 }
975
976 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
977 GElf_Word smax = gst->gst_file->gf_shnum;
978 mdb_gelf_sect_t *gsp;
979
980 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
981 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) {
982 gsp = &gst->gst_file->gf_sects[sym->st_shndx];
983 sym->st_value += gsp->gs_shdr.sh_offset;
984
985 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL ||
986 sym->st_size != 0)
987 asrsv++; /* reserve space in asmap */
988 }
989 }
990 }
991
992 gst->gst_asmap = mdb_alloc(sizeof (Elf32_Sym *) * asrsv, UM_SLEEP);
993 gst->gst_asrsv = asrsv;
994
995 gelf32_symtab_sort(gst);
996 }
997
998 static void
gelf64_symtab_sort(mdb_gelf_symtab_t * gst)999 gelf64_symtab_sort(mdb_gelf_symtab_t *gst)
1000 {
1001 Elf64_Sym **sympp = (Elf64_Sym **)gst->gst_asmap;
1002 mdb_var_t *v;
1003
1004 mdb_nv_rewind(&gst->gst_nv);
1005
1006 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
1007 Elf64_Sym *sym = MDB_NV_COOKIE(v);
1008 if (sym->st_value != 0 &&
1009 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
1010 *sympp++ = sym;
1011 }
1012
1013 gst->gst_aslen = (size_t)(sympp - (Elf64_Sym **)gst->gst_asmap);
1014 ASSERT(gst->gst_aslen <= gst->gst_asrsv);
1015
1016 gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL;
1017
1018 qsort(gst->gst_asmap, gst->gst_aslen,
1019 sizeof (Elf64_Sym *), gelf64_sym_compare);
1020
1021 gelf_strtab = NULL;
1022 }
1023
1024 static void
gelf64_symtab_init(mdb_gelf_symtab_t * gst)1025 gelf64_symtab_init(mdb_gelf_symtab_t *gst)
1026 {
1027 #if STT_NUM != (STT_TLS + 1)
1028 #error "STT_NUM has grown. update gelf64_symtab_init()"
1029 #endif
1030
1031 const char *base = (const char *)gst->gst_ssect->gs_data;
1032 Elf64_Sym *sym = gst->gst_dsect->gs_data;
1033 mdb_nv_t *nv = &gst->gst_nv;
1034
1035 Elf64_Xword ss_size = gst->gst_ssect->gs_shdr.sh_size;
1036 size_t asrsv = 0;
1037 GElf_Word i, n;
1038
1039 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf64_Sym)) {
1040 warn("%s sh_entsize %llu != sizeof (Elf64_Sym); "
1041 "using %u instead\n", gst->gst_dsect->gs_name,
1042 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize,
1043 (uint_t)sizeof (Elf64_Sym));
1044 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf64_Sym);
1045 }
1046
1047 n = gst->gst_dsect->gs_shdr.sh_size /
1048 gst->gst_dsect->gs_shdr.sh_entsize;
1049
1050 for (i = 0; i < n; i++, sym++) {
1051 const char *name = base + sym->st_name;
1052 uchar_t type = ELF64_ST_TYPE(sym->st_info);
1053
1054 if (type >= STT_NUM || type == STT_SECTION)
1055 continue; /* skip sections and unknown types */
1056
1057 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') {
1058 if (sym->st_name >= ss_size || name[0] != '\0') {
1059 warn("ignoring %s symbol [%u]: invalid name\n",
1060 gst->gst_dsect->gs_name, i);
1061 sym->st_name = 0;
1062 }
1063 continue; /* skip corrupt or empty names */
1064 }
1065
1066 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG);
1067
1068 if (sym->st_value != 0 &&
1069 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
1070 asrsv++; /* reserve space in the address map */
1071 }
1072
1073 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
1074 GElf_Word smax = gst->gst_file->gf_shnum;
1075 mdb_gelf_sect_t *gsp;
1076
1077 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
1078 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) {
1079 gsp = &gst->gst_file->gf_sects[sym->st_shndx];
1080 sym->st_value += gsp->gs_shdr.sh_offset;
1081
1082 if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL ||
1083 sym->st_size != 0)
1084 asrsv++; /* reserve space in asmap */
1085 }
1086 }
1087 }
1088
1089 gst->gst_asmap = mdb_alloc(sizeof (Elf64_Sym *) * asrsv, UM_SLEEP);
1090 gst->gst_asrsv = asrsv;
1091
1092 gelf64_symtab_sort(gst);
1093 }
1094
1095 mdb_gelf_symtab_t *
mdb_gelf_symtab_create_file(mdb_gelf_file_t * gf,GElf_Word elftype,uint_t tabid)1096 mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype,
1097 uint_t tabid)
1098 {
1099 mdb_gelf_sect_t *gsp;
1100 const char *dsname = NULL;
1101 const char *ssname;
1102 size_t i;
1103 GElf_Word link;
1104
1105 /*
1106 * Examine the sh_link field in the the Elf header to get the name
1107 * of the corresponding strings section
1108 */
1109 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1110 if (gsp->gs_shdr.sh_type == elftype) {
1111 dsname = gsp->gs_name;
1112 link = gsp->gs_shdr.sh_link;
1113 break;
1114 }
1115 }
1116
1117 if (dsname == NULL)
1118 return (NULL);
1119
1120 if (link > gf->gf_shnum) {
1121 /*
1122 * Invalid link number due to corrupt elf file.
1123 */
1124 warn("link number %ud larger than number of sections %d\n",
1125 link, gf->gf_shnum);
1126 return (NULL);
1127 }
1128
1129 ssname = (gf->gf_sects + link)->gs_name;
1130
1131 return (mdb_gelf_symtab_create_file_by_name(gf, dsname, ssname, tabid));
1132 }
1133
1134 mdb_gelf_symtab_t *
mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t * gf,const char * dsname,const char * ssname,uint_t tabid)1135 mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf,
1136 const char *dsname, const char *ssname, uint_t tabid)
1137 {
1138 mdb_gelf_symtab_t *gst;
1139 mdb_gelf_sect_t *gsp;
1140 size_t i;
1141
1142 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1143 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1144
1145 gst->gst_asmap = NULL;
1146 gst->gst_aslen = 0;
1147 gst->gst_asrsv = 0;
1148 gst->gst_ehdr = &gf->gf_ehdr;
1149 gst->gst_file = gf;
1150 gst->gst_dsect = NULL;
1151 gst->gst_ssect = NULL;
1152 gst->gst_id = 0;
1153 gst->gst_tabid = tabid;
1154
1155 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1156 if (strcmp(gsp->gs_name, dsname) == 0) {
1157 gst->gst_dsect = gsp;
1158 break;
1159 }
1160 }
1161
1162 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1163 if (strcmp(gsp->gs_name, ssname) == 0) {
1164 gst->gst_ssect = gsp;
1165 break;
1166 }
1167 }
1168
1169 if (gst->gst_dsect == NULL || gst->gst_ssect == NULL)
1170 goto err; /* Failed to locate data or string section */
1171
1172 if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL)
1173 goto err; /* Failed to load data section */
1174
1175 if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL)
1176 goto err; /* Failed to load string section */
1177
1178 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32)
1179 gelf32_symtab_init(gst);
1180 else
1181 gelf64_symtab_init(gst);
1182
1183 return (gst);
1184
1185 err:
1186 mdb_nv_destroy(&gst->gst_nv);
1187 mdb_free(gst, sizeof (mdb_gelf_symtab_t));
1188 return (NULL);
1189 }
1190
1191 mdb_gelf_symtab_t *
mdb_gelf_symtab_create_raw(const GElf_Ehdr * ehdr,const void * dshdr,void * ddata,const void * sshdr,void * sdata,uint_t tabid)1192 mdb_gelf_symtab_create_raw(const GElf_Ehdr *ehdr, const void *dshdr,
1193 void *ddata, const void *sshdr, void *sdata, uint_t tabid)
1194 {
1195 mdb_gelf_symtab_t *gst;
1196
1197 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1198 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1199
1200 gst->gst_asmap = NULL;
1201 gst->gst_aslen = 0;
1202 gst->gst_asrsv = 0;
1203 gst->gst_ehdr = ehdr;
1204 gst->gst_file = NULL; /* Flag for raw symtab */
1205 gst->gst_id = 0;
1206 gst->gst_tabid = tabid;
1207
1208 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1209 gst->gst_dsect->gs_name = ".symtab";
1210 gst->gst_dsect->gs_data = ddata;
1211
1212 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1213 gst->gst_ssect->gs_name = ".strtab";
1214 gst->gst_ssect->gs_data = sdata;
1215
1216 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1217 (void) gelf32_to_shdr(dshdr, &gst->gst_dsect->gs_shdr);
1218 (void) gelf32_to_shdr(sshdr, &gst->gst_ssect->gs_shdr);
1219 gelf32_symtab_init(gst);
1220 } else {
1221 (void) gelf64_to_shdr(dshdr, &gst->gst_dsect->gs_shdr);
1222 (void) gelf64_to_shdr(sshdr, &gst->gst_ssect->gs_shdr);
1223 gelf64_symtab_init(gst);
1224 }
1225
1226 return (gst);
1227 }
1228
1229 mdb_gelf_symtab_t *
mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t * gf,uint_t tabid)1230 mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t *gf, uint_t tabid)
1231 {
1232 GElf_Addr dt_symtab, dt_strtab, dt_hash;
1233 GElf_Xword dt_syment, dt_strsz;
1234
1235 mdb_gelf_symtab_t *gst;
1236 uint_t hash_h[2];
1237 off64_t base = 0;
1238
1239 ASSERT(gf->gf_mode == GF_PROGRAM);
1240
1241 /*
1242 * Read in and cache the array of GElf_Dyn structures from the
1243 * PT_DYNAMIC phdr. Abort if this is not possible.
1244 */
1245 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1246 (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn),
1247 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn);
1248 } else {
1249 (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn),
1250 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn);
1251 }
1252
1253 /*
1254 * Pre-fetch all the DT_* entries we will need for creating the
1255 * dynamic symbol table; abort if any are missing.
1256 */
1257 if ((dt_hash = gelf_dyn_lookup(gf, DT_HASH)) == -1L) {
1258 warn("failed to get DT_HASH for %s\n", IOP_NAME(gf->gf_io));
1259 return (NULL);
1260 }
1261
1262 if ((dt_symtab = gelf_dyn_lookup(gf, DT_SYMTAB)) == -1L) {
1263 warn("failed to get DT_SYMTAB for %s\n", IOP_NAME(gf->gf_io));
1264 return (NULL);
1265 }
1266
1267 if ((dt_syment = gelf_dyn_lookup(gf, DT_SYMENT)) == -1L) {
1268 warn("failed to get DT_SYMENT for %s\n", IOP_NAME(gf->gf_io));
1269 return (NULL);
1270 }
1271
1272 if ((dt_strtab = gelf_dyn_lookup(gf, DT_STRTAB)) == -1L) {
1273 warn("failed to get DT_STRTAB for %s\n", IOP_NAME(gf->gf_io));
1274 return (NULL);
1275 }
1276
1277 if ((dt_strsz = gelf_dyn_lookup(gf, DT_STRSZ)) == -1L) {
1278 warn("failed to get DT_STRSZ for %s\n", IOP_NAME(gf->gf_io));
1279 return (NULL);
1280 }
1281
1282 /*
1283 * If this is an executable, then DT_HASH is an absolute address;
1284 * we need to subtract the virtual base address of the mapping.
1285 */
1286 if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0)
1287 base = (off64_t)gf->gf_phdrs->p_vaddr;
1288
1289 /*
1290 * Read in the header for the DT_HASH: this consists of nbucket
1291 * and nchain values (nchain is the number of hashed symbols).
1292 */
1293 if (IOP_SEEK(gf->gf_io, (off64_t)dt_hash - base, SEEK_SET) == -1) {
1294 warn("failed to seek ELF file to start of DT_HASH");
1295 return (NULL);
1296 }
1297
1298 if (IOP_READ(gf->gf_io, hash_h, sizeof (hash_h)) != sizeof (hash_h)) {
1299 warn("failed to read DT_HASH header");
1300 return (NULL);
1301 }
1302
1303 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1304 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1305
1306 gst->gst_asmap = NULL;
1307 gst->gst_aslen = 0;
1308 gst->gst_asrsv = 0;
1309 gst->gst_ehdr = &gf->gf_ehdr;
1310 gst->gst_file = gf;
1311 gst->gst_id = 0;
1312 gst->gst_tabid = tabid;
1313
1314 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1315 gst->gst_dsect->gs_name = ".dynsym";
1316 gst->gst_dsect->gs_shdr.sh_offset = dt_symtab - (GElf_Addr)base;
1317 gst->gst_dsect->gs_shdr.sh_size = hash_h[1] * dt_syment;
1318 gst->gst_dsect->gs_shdr.sh_entsize = dt_syment;
1319
1320 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1321 gst->gst_ssect->gs_name = ".dynstr";
1322 gst->gst_ssect->gs_shdr.sh_offset = dt_strtab - (GElf_Addr)base;
1323 gst->gst_ssect->gs_shdr.sh_size = dt_strsz;
1324 gst->gst_ssect->gs_shdr.sh_entsize = 0;
1325
1326 if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL)
1327 goto err;
1328
1329 if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL)
1330 goto err;
1331
1332 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32)
1333 gelf32_symtab_init(gst);
1334 else
1335 gelf64_symtab_init(gst);
1336
1337 return (gst);
1338
1339 err:
1340 mdb_gelf_symtab_destroy(gst);
1341 return (NULL);
1342 }
1343
1344 mdb_gelf_symtab_t *
mdb_gelf_symtab_create_mutable(void)1345 mdb_gelf_symtab_create_mutable(void)
1346 {
1347 mdb_gelf_symtab_t *gst;
1348 static GElf_Ehdr ehdr;
1349
1350 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1351 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1352 gst->gst_ehdr = &ehdr;
1353
1354 if (ehdr.e_version == 0) {
1355 #ifdef _LP64
1356 uchar_t class = ELFCLASS64;
1357 #else
1358 uchar_t class = ELFCLASS32;
1359 #endif
1360
1361 #ifdef _BIG_ENDIAN
1362 uchar_t data = ELFDATA2MSB;
1363 #else
1364 uchar_t data = ELFDATA2LSB;
1365 #endif
1366 /*
1367 * Since all mutable symbol tables will use a native Ehdr,
1368 * we can just have a single static copy which they all
1369 * point to and we only need initialize once.
1370 */
1371 ehdr.e_ident[EI_MAG0] = ELFMAG0;
1372 ehdr.e_ident[EI_MAG1] = ELFMAG1;
1373 ehdr.e_ident[EI_MAG2] = ELFMAG2;
1374 ehdr.e_ident[EI_MAG3] = ELFMAG3;
1375 ehdr.e_ident[EI_CLASS] = class;
1376 ehdr.e_ident[EI_DATA] = data;
1377 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
1378 ehdr.e_type = ET_NONE;
1379 ehdr.e_version = EV_CURRENT;
1380 }
1381
1382 return (gst);
1383 }
1384
1385 void
mdb_gelf_symtab_destroy(mdb_gelf_symtab_t * gst)1386 mdb_gelf_symtab_destroy(mdb_gelf_symtab_t *gst)
1387 {
1388 if (gst->gst_file == NULL) {
1389 if (gst->gst_dsect == NULL && gst->gst_ssect == NULL) {
1390 mdb_var_t *v;
1391
1392 mdb_nv_rewind(&gst->gst_nv);
1393 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
1394 char *name = (char *)mdb_nv_get_name(v);
1395 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1396
1397 mdb_free(name, strlen(name) + 1);
1398 mdb_free(dsp, sizeof (mdb_gelf_dsym_t));
1399 }
1400
1401 } else {
1402 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t));
1403 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t));
1404 }
1405
1406 } else if (gst->gst_file->gf_mode == GF_PROGRAM) {
1407 mdb_gelf_sect_t *dsect = gst->gst_dsect;
1408 mdb_gelf_sect_t *ssect = gst->gst_ssect;
1409
1410 if (dsect->gs_data != NULL)
1411 mdb_free(dsect->gs_data, dsect->gs_shdr.sh_size);
1412 if (ssect->gs_data != NULL)
1413 mdb_free(ssect->gs_data, ssect->gs_shdr.sh_size);
1414
1415 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t));
1416 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t));
1417 }
1418
1419 mdb_nv_destroy(&gst->gst_nv);
1420 mdb_free(gst->gst_asmap, gst->gst_asrsv * sizeof (void *));
1421 mdb_free(gst, sizeof (mdb_gelf_symtab_t));
1422 }
1423
1424 size_t
mdb_gelf_symtab_size(mdb_gelf_symtab_t * gst)1425 mdb_gelf_symtab_size(mdb_gelf_symtab_t *gst)
1426 {
1427 return (mdb_nv_size(&gst->gst_nv));
1428 }
1429
1430 static GElf_Sym *
gelf32_to_sym(const Elf32_Sym * src,GElf_Sym * dst)1431 gelf32_to_sym(const Elf32_Sym *src, GElf_Sym *dst)
1432 {
1433 if (src != NULL) {
1434 dst->st_name = src->st_name;
1435 dst->st_info = src->st_info;
1436 dst->st_other = src->st_other;
1437 dst->st_shndx = src->st_shndx;
1438 dst->st_value = src->st_value;
1439 dst->st_size = src->st_size;
1440 return (dst);
1441 }
1442
1443 return (NULL);
1444 }
1445
1446 static GElf_Sym *
gelf64_to_sym(const Elf64_Sym * src,GElf_Sym * dst)1447 gelf64_to_sym(const Elf64_Sym *src, GElf_Sym *dst)
1448 {
1449 if (src != NULL) {
1450 bcopy(src, dst, sizeof (GElf_Sym));
1451 return (dst);
1452 }
1453
1454 return (NULL);
1455 }
1456
1457 /*ARGSUSED*/
1458 static GElf_Sym *
gelf64_nocopy(const Elf64_Sym * src,GElf_Sym * dst)1459 gelf64_nocopy(const Elf64_Sym *src, GElf_Sym *dst)
1460 {
1461 return ((GElf_Sym *)src);
1462 }
1463
1464 static const void *
gelf32_sym_search(const Elf32_Sym ** asmap,size_t aslen,uintptr_t addr)1465 gelf32_sym_search(const Elf32_Sym **asmap, size_t aslen, uintptr_t addr)
1466 {
1467 ulong_t i, mid, lo = 0, hi = aslen - 1;
1468 const Elf32_Sym *symp;
1469 Elf32_Addr v;
1470 size_t size;
1471
1472 if (aslen == 0)
1473 return (NULL);
1474
1475 while (hi - lo > 1) {
1476 mid = (lo + hi) / 2;
1477 if (addr >= asmap[mid]->st_value)
1478 lo = mid;
1479 else
1480 hi = mid;
1481 }
1482
1483 i = addr < asmap[hi]->st_value ? lo : hi;
1484 symp = asmap[i];
1485 v = symp->st_value;
1486
1487 /*
1488 * If the previous entry has the same value, improve our choice. The
1489 * order of equal-valued symbols is determined by gelf32_sym_compare().
1490 */
1491 while (i-- != 0 && asmap[i]->st_value == v)
1492 symp = asmap[i];
1493
1494 /*
1495 * If an absolute symbol distance was specified, use that; otherwise
1496 * use the ELF symbol size, or 1 byte if the ELF size is zero.
1497 */
1498 if (mdb.m_symdist == 0)
1499 size = MAX(symp->st_size, 1);
1500 else
1501 size = mdb.m_symdist;
1502
1503 if (addr - symp->st_value < size)
1504 return (symp);
1505
1506 return (NULL);
1507 }
1508
1509 static const void *
gelf64_sym_search(const Elf64_Sym ** asmap,size_t aslen,uintptr_t addr)1510 gelf64_sym_search(const Elf64_Sym **asmap, size_t aslen, uintptr_t addr)
1511 {
1512 ulong_t i, mid, lo = 0, hi = aslen - 1;
1513 const Elf64_Sym *symp;
1514 Elf64_Addr v;
1515 size_t size;
1516
1517 if (aslen == 0)
1518 return (NULL);
1519
1520 while (hi - lo > 1) {
1521 mid = (lo + hi) / 2;
1522 if (addr >= asmap[mid]->st_value)
1523 lo = mid;
1524 else
1525 hi = mid;
1526 }
1527
1528 i = addr < asmap[hi]->st_value ? lo : hi;
1529 symp = asmap[i];
1530 v = symp->st_value;
1531
1532 /*
1533 * If the previous entry has the same value, improve our choice. The
1534 * order of equal-valued symbols is determined by gelf64_sym_compare().
1535 */
1536 while (i-- != 0 && asmap[i]->st_value == v)
1537 symp = asmap[i];
1538
1539 /*
1540 * If an absolute symbol distance was specified, use that; otherwise
1541 * use the ELF symbol size, or 1 byte if the ELF size is zero.
1542 */
1543 if (mdb.m_symdist == 0)
1544 size = MAX(symp->st_size, 1);
1545 else
1546 size = mdb.m_symdist;
1547
1548 if (addr - symp->st_value < size)
1549 return (symp);
1550
1551 return (NULL);
1552 }
1553
1554 const char *
mdb_gelf_sym_name(mdb_gelf_symtab_t * gst,const GElf_Sym * sym)1555 mdb_gelf_sym_name(mdb_gelf_symtab_t *gst, const GElf_Sym *sym)
1556 {
1557 const mdb_gelf_dsym_t *dsp;
1558
1559 if (gst->gst_ssect != NULL)
1560 return ((const char *)gst->gst_ssect->gs_data + sym->st_name);
1561
1562 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1563 dsp = gelf32_sym_search(gst->gst_asmap,
1564 gst->gst_aslen, sym->st_value);
1565 else
1566 dsp = gelf64_sym_search(gst->gst_asmap,
1567 gst->gst_aslen, sym->st_value);
1568
1569 if (dsp != NULL)
1570 return (mdb_nv_get_name(dsp->ds_var));
1571
1572 return (NULL);
1573 }
1574
1575 int
mdb_gelf_sym_closer(const GElf_Sym * s1,const GElf_Sym * s2,uintptr_t addr)1576 mdb_gelf_sym_closer(const GElf_Sym *s1, const GElf_Sym *s2, uintptr_t addr)
1577 {
1578 uintptr_t v1 = (uintptr_t)s1->st_value;
1579 uintptr_t v2 = (uintptr_t)s2->st_value;
1580
1581 uintptr_t d1 = v1 > addr ? v1 - addr : addr - v1;
1582 uintptr_t d2 = v2 > addr ? v2 - addr : addr - v2;
1583
1584 return (d1 < d2);
1585 }
1586
1587 int
mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t * gst,uintptr_t addr,uint_t flags,char * buf,size_t nbytes,GElf_Sym * sym,uint_t * idp)1588 mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t *gst, uintptr_t addr,
1589 uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym, uint_t *idp)
1590 {
1591 union {
1592 const mdb_gelf_dsym_t *dsp;
1593 const Elf32_Sym *s32;
1594 const Elf64_Sym *s64;
1595 caddr_t sp;
1596 } u;
1597
1598 const char *name;
1599
1600 if (gst == NULL)
1601 return (set_errno(EMDB_NOSYMADDR));
1602
1603 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1604 u.s32 = gelf32_sym_search(gst->gst_asmap, gst->gst_aslen, addr);
1605 if (gelf32_to_sym(u.s32, sym) == NULL)
1606 return (set_errno(EMDB_NOSYMADDR));
1607 } else {
1608 u.s64 = gelf64_sym_search(gst->gst_asmap, gst->gst_aslen, addr);
1609 if (gelf64_to_sym(u.s64, sym) == NULL)
1610 return (set_errno(EMDB_NOSYMADDR));
1611 }
1612
1613 if ((flags & GST_EXACT) && (sym->st_value != addr))
1614 return (set_errno(EMDB_NOSYMADDR));
1615
1616 if (gst->gst_ssect != NULL) {
1617 name = (const char *)gst->gst_ssect->gs_data + sym->st_name;
1618 if (idp != NULL) {
1619 *idp = (u.sp - (caddr_t)gst->gst_dsect->gs_data) /
1620 gst->gst_dsect->gs_shdr.sh_entsize;
1621 }
1622 } else {
1623 name = mdb_nv_get_name(u.dsp->ds_var);
1624 if (idp != NULL)
1625 *idp = u.dsp->ds_id;
1626 }
1627
1628 if (nbytes > 0) {
1629 (void) strncpy(buf, name, nbytes - 1);
1630 buf[nbytes - 1] = '\0';
1631 }
1632 return (0);
1633 }
1634
1635 int
mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t * gst,const char * name,GElf_Sym * sym,uint_t * idp)1636 mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t *gst, const char *name,
1637 GElf_Sym *sym, uint_t *idp)
1638 {
1639 mdb_var_t *v;
1640
1641 if (gst != NULL && (v = mdb_nv_lookup(&gst->gst_nv, name)) != NULL) {
1642 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1643 (void) gelf32_to_sym(mdb_nv_get_cookie(v), sym);
1644 else
1645 (void) gelf64_to_sym(mdb_nv_get_cookie(v), sym);
1646
1647 if (idp != NULL) {
1648 if (gst->gst_file == NULL && gst->gst_dsect == NULL) {
1649 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1650 *idp = dsp->ds_id;
1651 } else {
1652 *idp = ((uintptr_t)mdb_nv_get_cookie(v) -
1653 (uintptr_t)gst->gst_dsect->gs_data) /
1654 gst->gst_dsect->gs_shdr.sh_entsize;
1655 }
1656 }
1657
1658 return (0);
1659 }
1660
1661 return (set_errno(EMDB_NOSYM));
1662 }
1663
1664 int
mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t * gst,const char * file,const char * name,GElf_Sym * sym,uint_t * idp)1665 mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t *gst, const char *file,
1666 const char *name, GElf_Sym *sym, uint_t *idp)
1667 {
1668 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *);
1669 size_t sym_size;
1670 caddr_t sp, ep;
1671 mdb_var_t *v;
1672
1673 if (gst == NULL)
1674 return (set_errno(EMDB_NOSYM));
1675
1676 if ((v = mdb_nv_lookup(&gst->gst_nv, file)) == NULL)
1677 return (set_errno(EMDB_NOOBJ));
1678
1679 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1680 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym;
1681 sym_size = sizeof (Elf32_Sym);
1682 } else {
1683 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_to_sym;
1684 sym_size = sizeof (Elf64_Sym);
1685 }
1686
1687 (void) s2gelf(mdb_nv_get_cookie(v), sym);
1688
1689 if (GELF_ST_TYPE(sym->st_info) != STT_FILE)
1690 return (set_errno(EMDB_NOOBJ));
1691
1692 ep = (caddr_t)gst->gst_dsect->gs_data + gst->gst_dsect->gs_shdr.sh_size;
1693 sp = (caddr_t)mdb_nv_get_cookie(v);
1694
1695 /*
1696 * We assume that symbol lookups scoped by source file name are only
1697 * relevant for userland debugging and are a relatively rare request,
1698 * and so we use a simple but inefficient linear search with copying.
1699 */
1700 for (sp += sym_size; sp < ep; sp += sym_size) {
1701 (void) s2gelf(sp, sym); /* Convert native symbol to GElf */
1702
1703 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION ||
1704 GELF_ST_TYPE(sym->st_info) == STT_FILE ||
1705 GELF_ST_BIND(sym->st_info) != STB_LOCAL)
1706 break; /* End of this file's locals */
1707
1708 if (strcmp(mdb_gelf_sym_name(gst, sym), name) == 0) {
1709 if (idp != NULL) {
1710 *idp = (sp - (caddr_t)
1711 gst->gst_dsect->gs_data) / sym_size;
1712 }
1713 return (0);
1714 }
1715 }
1716
1717 return (set_errno(EMDB_NOSYM));
1718 }
1719
1720 void
mdb_gelf_symtab_iter(mdb_gelf_symtab_t * gst,int (* func)(void *,const GElf_Sym *,const char *,uint_t),void * private)1721 mdb_gelf_symtab_iter(mdb_gelf_symtab_t *gst, int (*func)(void *,
1722 const GElf_Sym *, const char *, uint_t), void *private)
1723 {
1724 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *);
1725 GElf_Sym sym, *symp;
1726 size_t sym_size;
1727
1728 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1729 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym;
1730 sym_size = sizeof (Elf32_Sym);
1731 } else {
1732 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_nocopy;
1733 sym_size = sizeof (Elf64_Sym);
1734 }
1735
1736 /*
1737 * If this is a mutable symbol table, we iterate over the hash table
1738 * of symbol names; otherwise we go iterate over the data buffer. For
1739 * non-mutable tables, this means that ::nm will show all symbols,
1740 * including those with duplicate names (not present in gst_nv).
1741 */
1742 if (gst->gst_file == NULL && gst->gst_dsect == NULL) {
1743 mdb_gelf_dsym_t *dsp;
1744 mdb_var_t *v;
1745
1746 mdb_nv_rewind(&gst->gst_nv);
1747 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
1748 dsp = mdb_nv_get_cookie(v);
1749 symp = s2gelf(dsp, &sym);
1750 if (func(private, symp, mdb_nv_get_name(v),
1751 dsp->ds_id) == -1)
1752 break;
1753 }
1754
1755 } else {
1756 const char *sbase = gst->gst_ssect->gs_data;
1757 caddr_t sp = gst->gst_dsect->gs_data;
1758 caddr_t ep = sp + gst->gst_dsect->gs_shdr.sh_size;
1759 uint_t i;
1760
1761 for (i = 0; sp < ep; sp += sym_size, i++) {
1762 symp = s2gelf(sp, &sym);
1763 if (func(private, symp, sbase + symp->st_name, i) == -1)
1764 break;
1765 }
1766 }
1767 }
1768
1769 static void
gelf_sym_to_32(const GElf_Sym * src,Elf32_Sym * dst)1770 gelf_sym_to_32(const GElf_Sym *src, Elf32_Sym *dst)
1771 {
1772 dst->st_name = src->st_name;
1773 dst->st_info = src->st_info;
1774 dst->st_other = src->st_other;
1775 dst->st_shndx = src->st_shndx;
1776 dst->st_value = (Elf32_Addr)src->st_value;
1777 dst->st_size = (Elf32_Word)src->st_size;
1778 }
1779
1780 static void
gelf_sym_to_64(const GElf_Sym * src,Elf64_Sym * dst)1781 gelf_sym_to_64(const GElf_Sym *src, Elf64_Sym *dst)
1782 {
1783 bcopy(src, dst, sizeof (Elf64_Sym));
1784 }
1785
1786 void
mdb_gelf_symtab_insert(mdb_gelf_symtab_t * gst,const char * name,const GElf_Sym * symp)1787 mdb_gelf_symtab_insert(mdb_gelf_symtab_t *gst,
1788 const char *name, const GElf_Sym *symp)
1789 {
1790 mdb_gelf_dsym_t *dsp;
1791 mdb_var_t *v;
1792
1793 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL);
1794 v = mdb_nv_lookup(&gst->gst_nv, name);
1795
1796 if (v == NULL) {
1797 char *s = mdb_alloc(strlen(name) + 1, UM_SLEEP);
1798 (void) strcpy(s, name);
1799
1800 dsp = mdb_alloc(sizeof (mdb_gelf_dsym_t), UM_SLEEP);
1801 dsp->ds_id = gst->gst_id++;
1802
1803 dsp->ds_var = mdb_nv_insert(&gst->gst_nv, s, NULL,
1804 (uintptr_t)dsp, GST_NVFLG);
1805
1806 gst->gst_aslen++;
1807 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv));
1808
1809 if (gst->gst_aslen > gst->gst_asrsv) {
1810 mdb_free(gst->gst_asmap,
1811 sizeof (void *) * gst->gst_asrsv);
1812
1813 gst->gst_asrsv = gst->gst_asrsv != 0 ?
1814 gst->gst_asrsv * GST_GROW : GST_DEFSZ;
1815
1816 gst->gst_asmap = mdb_alloc(sizeof (void *) *
1817 gst->gst_asrsv, UM_SLEEP);
1818 }
1819 } else
1820 dsp = mdb_nv_get_cookie(v);
1821
1822 mdb_dprintf(MDB_DBG_ELF, "added symbol (\"%s\", %llx)\n",
1823 name, (u_longlong_t)symp->st_value);
1824
1825 bcopy(symp, &dsp->ds_sym, sizeof (GElf_Sym));
1826 dsp->ds_sym.st_name = (uintptr_t)mdb_nv_get_name(dsp->ds_var);
1827
1828 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1829 gelf_sym_to_32(symp, &dsp->ds_u.ds_s32);
1830 gelf32_symtab_sort(gst);
1831 } else {
1832 gelf_sym_to_64(symp, &dsp->ds_u.ds_s64);
1833 gelf64_symtab_sort(gst);
1834 }
1835 }
1836
1837 void
mdb_gelf_symtab_delete(mdb_gelf_symtab_t * gst,const char * name,GElf_Sym * symp)1838 mdb_gelf_symtab_delete(mdb_gelf_symtab_t *gst,
1839 const char *name, GElf_Sym *symp)
1840 {
1841 mdb_var_t *v;
1842
1843 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL);
1844 v = mdb_nv_lookup(&gst->gst_nv, name);
1845
1846 if (v != NULL) {
1847 char *name = (char *)mdb_nv_get_name(v);
1848 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1849
1850 if (symp != NULL)
1851 bcopy(&dsp->ds_sym, symp, sizeof (GElf_Sym));
1852
1853 mdb_dprintf(MDB_DBG_ELF, "removed symbol (\"%s\", %llx)\n",
1854 name, (u_longlong_t)dsp->ds_sym.st_value);
1855
1856 mdb_nv_remove(&gst->gst_nv, v);
1857 gst->gst_aslen--;
1858 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv));
1859
1860 mdb_free(name, strlen(name) + 1);
1861 mdb_free(dsp, sizeof (mdb_gelf_dsym_t));
1862
1863 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1864 gelf32_symtab_sort(gst);
1865 else
1866 gelf64_symtab_sort(gst);
1867 }
1868 }
1869
1870 static const GElf_Phdr *
gelf_phdr_lookup(mdb_gelf_file_t * gf,uintptr_t addr)1871 gelf_phdr_lookup(mdb_gelf_file_t *gf, uintptr_t addr)
1872 {
1873 const GElf_Phdr *gpp = gf->gf_phdrs;
1874 size_t i;
1875
1876 for (i = 0; i < gf->gf_npload; i++, gpp++) {
1877 if (addr >= gpp->p_vaddr && addr < gpp->p_vaddr + gpp->p_memsz)
1878 return (gpp);
1879 }
1880
1881 return (NULL);
1882 }
1883
1884 ssize_t
mdb_gelf_rw(mdb_gelf_file_t * gf,void * buf,size_t nbytes,uintptr_t addr,ssize_t (* prw)(mdb_io_t *,void *,size_t),mdb_gelf_rw_t rw)1885 mdb_gelf_rw(mdb_gelf_file_t *gf, void *buf, size_t nbytes, uintptr_t addr,
1886 ssize_t (*prw)(mdb_io_t *, void *, size_t), mdb_gelf_rw_t rw)
1887 {
1888 ssize_t resid = nbytes;
1889
1890 while (resid != 0) {
1891 const GElf_Phdr *php = gelf_phdr_lookup(gf, addr);
1892
1893 uintptr_t mapoff;
1894 ssize_t memlen, filelen, len = 0;
1895 off64_t off;
1896
1897 if (php == NULL)
1898 break; /* No mapping for this address */
1899
1900 mapoff = addr - php->p_vaddr;
1901 memlen = MIN(resid, php->p_memsz - mapoff);
1902 filelen = MIN(resid, php->p_filesz - mapoff);
1903 off = (off64_t)php->p_offset + mapoff;
1904
1905 if (filelen > 0 && (IOP_SEEK(gf->gf_io, off, SEEK_SET) != off ||
1906 (len = prw(gf->gf_io, buf, filelen)) <= 0))
1907 break;
1908
1909 if (rw == GIO_READ && len == filelen && filelen < memlen) {
1910 bzero((char *)buf + len, memlen - filelen);
1911 len += memlen - filelen;
1912 }
1913
1914 resid -= len;
1915 addr += len;
1916 buf = (char *)buf + len;
1917 }
1918
1919 if (resid == nbytes && nbytes != 0)
1920 return (set_errno(EMDB_NOMAP));
1921
1922 return (nbytes - resid);
1923 }
1924
1925 mdb_gelf_sect_t *
mdb_gelf_sect_by_name(mdb_gelf_file_t * gf,const char * name)1926 mdb_gelf_sect_by_name(mdb_gelf_file_t *gf, const char *name)
1927 {
1928 size_t i;
1929
1930 for (i = 0; i < gf->gf_shnum; i++) {
1931 if (strcmp(gf->gf_sects[i].gs_name, name) == 0)
1932 return (&gf->gf_sects[i]);
1933 }
1934
1935 return (NULL);
1936 }
1937