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