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