xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_gelf.c (revision a576ab5b)
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 static GElf_Dyn *
472 gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size,
473     GElf_Dyn *(*elf2gelf)(const void *, GElf_Dyn *))
474 {
475 	size_t nbytes, ndyns, i;
476 	caddr_t dyns, dp;
477 	GElf_Dyn *gdp;
478 
479 	off64_t dyn_addr;
480 
481 	if (gf->gf_dyns != NULL)
482 		return (gf->gf_dyns);	/* Already loaded */
483 
484 	if (gf->gf_dynp == NULL)
485 		return (NULL);		/* No PT_DYNAMIC entry was found */
486 
487 	nbytes = gf->gf_dynp->p_filesz;
488 	ndyns = nbytes / dyn_size;
489 
490 	/*
491 	 * If this is an executable in PROGRAM view, then p_vaddr is an
492 	 * absolute address; we need to subtract the virtual base address of
493 	 * the mapping.  In FILE view, dyn_addr is just the file offset.
494 	 */
495 	if (gf->gf_mode == GF_PROGRAM) {
496 		if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0)
497 			dyn_addr = gf->gf_dynp->p_vaddr - gf->gf_phdrs->p_vaddr;
498 		else
499 			dyn_addr = gf->gf_dynp->p_vaddr;
500 	} else {
501 		mdb_gelf_sect_t *gsp = gf->gf_sects;
502 
503 		for (i = 0; i < gf->gf_shnum; i++, gsp++) {
504 			if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) {
505 				dyn_addr = gsp->gs_shdr.sh_offset;
506 				break;
507 			}
508 		}
509 
510 		if (i == gf->gf_shnum)
511 			return (NULL); /* No SHT_DYNAMIC entry was found */
512 	}
513 
514 	mdb_dprintf(MDB_DBG_ELF, "loading _DYNAMIC[] (%lu entries) "
515 	    "from offset %llx\n", (ulong_t)ndyns, (longlong_t)dyn_addr);
516 
517 	if (IOP_SEEK(gf->gf_io, dyn_addr, SEEK_SET) == -1) {
518 		warn("failed to seek %s to _DYNAMIC", IOP_NAME(gf->gf_io));
519 		return (NULL);
520 	}
521 
522 	dyns = mdb_alloc(nbytes, UM_SLEEP);
523 
524 	if (IOP_READ(gf->gf_io, dyns, nbytes) != nbytes) {
525 		warn("failed to read %s:_DYNAMIC", IOP_NAME(gf->gf_io));
526 		mdb_free(dyns, nbytes);
527 		return (NULL);
528 	}
529 
530 	gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP);
531 	gf->gf_ndyns = ndyns;
532 
533 	dp = dyns;
534 	gdp = gf->gf_dyns;
535 
536 	for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++)
537 		(void) elf2gelf(dp, gdp);
538 
539 	mdb_free(dyns, nbytes);
540 	return (gf->gf_dyns);
541 }
542 
543 static mdb_gelf_file_t *
544 gelf32_init(mdb_gelf_file_t *gf, mdb_io_t *io, const Elf32_Ehdr *ehdr)
545 {
546 	/*
547 	 * Convert the Elf32_Ehdr to a GElf_Ehdr
548 	 */
549 	bcopy(ehdr->e_ident, gf->gf_ehdr.e_ident, EI_NIDENT);
550 
551 	gf->gf_ehdr.e_type = ehdr->e_type;
552 	gf->gf_ehdr.e_machine = ehdr->e_machine;
553 	gf->gf_ehdr.e_version = ehdr->e_version;
554 	gf->gf_ehdr.e_entry = ehdr->e_entry;
555 	gf->gf_ehdr.e_phoff = ehdr->e_phoff;
556 	gf->gf_ehdr.e_shoff = ehdr->e_shoff;
557 	gf->gf_ehdr.e_flags = ehdr->e_flags;
558 	gf->gf_ehdr.e_ehsize = ehdr->e_ehsize;
559 	gf->gf_ehdr.e_phentsize = ehdr->e_phentsize;
560 	gf->gf_ehdr.e_phnum = ehdr->e_phnum;
561 	gf->gf_ehdr.e_shentsize = ehdr->e_shentsize;
562 	gf->gf_ehdr.e_shnum = ehdr->e_shnum;
563 	gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx;
564 
565 	gf->gf_shnum = gf->gf_ehdr.e_shnum;
566 	gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
567 	gf->gf_phnum = gf->gf_ehdr.e_phnum;
568 
569 	if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
570 	    gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
571 		Elf32_Shdr shdr0;
572 
573 		if (ehdr->e_shoff == 0)
574 			return (NULL);
575 
576 		if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
577 			warn("failed to seek %s", IOP_NAME(io));
578 			return (NULL);
579 		}
580 
581 		if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
582 			warn("failed to read extended ELF header from %s",
583 			    IOP_NAME(io));
584 			return (NULL);
585 		}
586 
587 		if (gf->gf_shnum == 0)
588 			gf->gf_shnum = shdr0.sh_size;
589 
590 		if (gf->gf_shstrndx == SHN_XINDEX)
591 			gf->gf_shstrndx = shdr0.sh_link;
592 
593 		if (gf->gf_phnum == PN_XNUM)
594 			gf->gf_phnum = shdr0.sh_info;
595 	}
596 
597 	/*
598 	 * Initialize the section and program headers.  We skip initializing
599 	 * the section headers if this is a program image because they are
600 	 * not loadable and thus we can't get at them.
601 	 */
602 	if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf32_Shdr),
603 	    (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf32_to_shdr) == NULL)
604 		return (NULL);
605 
606 	if (gelf_phdrs_init(gf, sizeof (Elf32_Phdr),
607 	    (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf32_to_phdr) == NULL)
608 		return (NULL);
609 
610 	(void) gelf_dyns_init(gf, sizeof (Elf32_Dyn),
611 	    (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn);
612 
613 	return (gf);
614 }
615 
616 static mdb_gelf_file_t *
617 gelf64_init(mdb_gelf_file_t *gf, mdb_io_t *io, Elf64_Ehdr *ehdr)
618 {
619 	/*
620 	 * Save a copy of the ELF file header
621 	 */
622 	bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr));
623 
624 	gf->gf_shnum = gf->gf_ehdr.e_shnum;
625 	gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
626 	gf->gf_phnum = gf->gf_ehdr.e_phnum;
627 
628 	if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
629 	    gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
630 		Elf64_Shdr shdr0;
631 
632 		if (ehdr->e_shoff == 0)
633 			return (NULL);
634 
635 		if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
636 			warn("failed to seek %s", IOP_NAME(io));
637 			return (NULL);
638 		}
639 
640 		if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
641 			warn("failed to read extended ELF header from %s",
642 			    IOP_NAME(io));
643 			return (NULL);
644 		}
645 
646 		if (gf->gf_shnum == 0)
647 			gf->gf_shnum = shdr0.sh_size;
648 
649 		if (gf->gf_shstrndx == SHN_XINDEX)
650 			gf->gf_shstrndx = shdr0.sh_link;
651 
652 		if (gf->gf_phnum == PN_XNUM)
653 			gf->gf_phnum = shdr0.sh_info;
654 	}
655 
656 	/*
657 	 * Initialize the section and program headers.  We skip initializing
658 	 * the section headers if this is a program image because they are
659 	 * not loadable and thus we can't get at them.
660 	 */
661 	if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf64_Shdr),
662 	    (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf64_to_shdr) == NULL)
663 		return (NULL);
664 
665 	if (gelf_phdrs_init(gf, sizeof (Elf64_Phdr),
666 	    (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf64_to_phdr) == NULL)
667 		return (NULL);
668 
669 	(void) gelf_dyns_init(gf, sizeof (Elf64_Dyn),
670 	    (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn);
671 
672 	return (gf);
673 }
674 
675 int
676 mdb_gelf_check(mdb_io_t *io, Elf32_Ehdr *ehp, GElf_Half etype)
677 {
678 #ifdef _BIG_ENDIAN
679 	uchar_t order = ELFDATA2MSB;
680 #else
681 	uchar_t order = ELFDATA2LSB;
682 #endif
683 	ssize_t nbytes;
684 
685 	(void) IOP_SEEK(io, (off64_t)0L, SEEK_SET);
686 	nbytes = IOP_READ(io, ehp, sizeof (Elf32_Ehdr));
687 
688 	if (nbytes == -1) {
689 		if (etype != ET_NONE)
690 			warn("failed to read ELF header from %s", IOP_NAME(io));
691 		return (-1);
692 	}
693 
694 	if (nbytes != sizeof (Elf32_Ehdr) ||
695 	    bcmp(&ehp->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) {
696 		if (etype != ET_NONE)
697 			warn("%s is not an ELF file\n", IOP_NAME(io));
698 		return (-1);
699 	}
700 
701 	if (ehp->e_ident[EI_DATA] != order) {
702 		warn("ELF file %s has different endianness from debugger\n",
703 		    IOP_NAME(io));
704 		return (-1);
705 	}
706 
707 	if (ehp->e_version != EV_CURRENT) {
708 		warn("ELF file %s uses different ELF version (%lu) than "
709 		    "debugger (%u)\n", IOP_NAME(io),
710 		    (ulong_t)ehp->e_version, EV_CURRENT);
711 		return (-1);
712 	}
713 
714 	if (etype != ET_NONE && ehp->e_type != etype) {
715 		warn("ELF file %s is not of the expected type\n", IOP_NAME(io));
716 		return (-1);
717 	}
718 
719 	return (0);
720 }
721 
722 mdb_gelf_file_t *
723 mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode)
724 {
725 	union {
726 		Elf32_Ehdr h32;
727 		Elf64_Ehdr h64;
728 	} ehdr;
729 
730 	mdb_gelf_file_t *gf = mdb_zalloc(sizeof (mdb_gelf_file_t), UM_SLEEP);
731 
732 	ASSERT(mode == GF_FILE || mode == GF_PROGRAM);
733 	gf->gf_mode = mode;
734 
735 	/*
736 	 * Assign the i/o backend now, but don't hold it until we're sure
737 	 * we're going to succeed; otherwise the caller will be responsible
738 	 * for mdb_io_destroy()ing it.
739 	 */
740 	gf->gf_io = io;
741 
742 	if (mdb_gelf_check(io, &ehdr.h32, etype) == -1)
743 		goto err;
744 
745 	switch (ehdr.h32.e_ident[EI_CLASS]) {
746 	case ELFCLASS32:
747 		gf = gelf32_init(gf, io, &ehdr.h32);
748 		break;
749 
750 	case ELFCLASS64:
751 		if (IOP_SEEK(io, (off64_t)0L, SEEK_SET) == -1) {
752 			warn("failed to seek %s", IOP_NAME(io));
753 			goto err;
754 		}
755 
756 		if (IOP_READ(io, &ehdr.h64, sizeof (ehdr.h64)) !=
757 		    sizeof (ehdr.h64)) {
758 			warn("failed to read ELF header from %s", IOP_NAME(io));
759 			goto err;
760 		}
761 
762 		gf = gelf64_init(gf, io, &ehdr.h64);
763 		break;
764 
765 	default:
766 		warn("%s is an unsupported ELF class: %u\n",
767 		    IOP_NAME(io), ehdr.h32.e_ident[EI_CLASS]);
768 		goto err;
769 	}
770 
771 	if (gf != NULL && gelf_sect_init(gf) != NULL) {
772 		gf->gf_io = mdb_io_hold(io);
773 		return (gf);
774 	}
775 
776 err:
777 	if (gf != NULL) {
778 		if (gf->gf_sects != NULL) {
779 			mdb_free(gf->gf_sects, gf->gf_shnum *
780 			    sizeof (mdb_gelf_sect_t));
781 		}
782 		mdb_free(gf, sizeof (mdb_gelf_file_t));
783 	}
784 	return (NULL);
785 }
786 
787 void
788 mdb_gelf_destroy(mdb_gelf_file_t *gf)
789 {
790 	mdb_gelf_sect_t *gsp;
791 	GElf_Half i;
792 
793 	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
794 		if (gsp->gs_data != NULL)
795 			mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size);
796 	}
797 
798 	mdb_free(gf->gf_sects,
799 	    gf->gf_shnum * sizeof (mdb_gelf_sect_t));
800 
801 	mdb_free(gf->gf_phdrs, gf->gf_phnum * sizeof (GElf_Phdr));
802 
803 	mdb_io_rele(gf->gf_io);
804 	mdb_free(gf, sizeof (mdb_gelf_file_t));
805 }
806 
807 /*
808  * Sort comparison function for 32-bit symbol address-to-name lookups.  We sort
809  * symbols by value.  If values are equal, we prefer the symbol that is
810  * non-zero sized, typed, not weak, or lexically first, in that order.
811  */
812 static int
813 gelf32_sym_compare(const void *lp, const void *rp)
814 {
815 	Elf32_Sym *lhs = *((Elf32_Sym **)lp);
816 	Elf32_Sym *rhs = *((Elf32_Sym **)rp);
817 
818 	if (lhs->st_value != rhs->st_value)
819 		return (lhs->st_value > rhs->st_value ? 1 : -1);
820 
821 	if ((lhs->st_size == 0) != (rhs->st_size == 0))
822 		return (lhs->st_size == 0 ? 1 : -1);
823 
824 	if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
825 	    (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
826 		return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
827 
828 	if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
829 	    (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
830 		return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
831 
832 	return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name));
833 }
834 
835 /*
836  * Sort comparison function for 64-bit symbol address-to-name lookups.  We sort
837  * symbols by value.  If values are equal, we prefer the symbol that is
838  * non-zero sized, typed, not weak, or lexically first, in that order.
839  */
840 static int
841 gelf64_sym_compare(const void *lp, const void *rp)
842 {
843 	Elf64_Sym *lhs = *((Elf64_Sym **)lp);
844 	Elf64_Sym *rhs = *((Elf64_Sym **)rp);
845 
846 	if (lhs->st_value != rhs->st_value)
847 		return (lhs->st_value > rhs->st_value ? 1 : -1);
848 
849 	if ((lhs->st_size == 0) != (rhs->st_size == 0))
850 		return (lhs->st_size == 0 ? 1 : -1);
851 
852 	if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
853 	    (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
854 		return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
855 
856 	if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
857 	    (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
858 		return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
859 
860 	return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name));
861 }
862 
863 static void
864 gelf32_symtab_sort(mdb_gelf_symtab_t *gst)
865 {
866 	Elf32_Sym **sympp = (Elf32_Sym **)gst->gst_asmap;
867 	mdb_var_t *v;
868 
869 	mdb_nv_rewind(&gst->gst_nv);
870 
871 	while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
872 		Elf32_Sym *sym = MDB_NV_COOKIE(v);
873 		if (sym->st_value != 0 &&
874 		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
875 			*sympp++ = sym;
876 	}
877 
878 	gst->gst_aslen = (size_t)(sympp - (Elf32_Sym **)gst->gst_asmap);
879 	ASSERT(gst->gst_aslen <= gst->gst_asrsv);
880 
881 	gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL;
882 
883 	qsort(gst->gst_asmap, gst->gst_aslen,
884 	    sizeof (Elf32_Sym *), gelf32_sym_compare);
885 
886 	gelf_strtab = NULL;
887 }
888 
889 static void
890 gelf32_symtab_init(mdb_gelf_symtab_t *gst)
891 {
892 	const char *base = (const char *)gst->gst_ssect->gs_data;
893 	Elf32_Sym *sym = gst->gst_dsect->gs_data;
894 	mdb_nv_t *nv = &gst->gst_nv;
895 
896 	Elf32_Word ss_size = gst->gst_ssect->gs_shdr.sh_size;
897 	size_t asrsv = 0;
898 	GElf_Word i, n;
899 
900 	if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf32_Sym)) {
901 		warn("%s sh_entsize %llu != sizeof (Elf32_Sym); "
902 		    "using %u instead\n", gst->gst_dsect->gs_name,
903 		    (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize,
904 		    (uint_t)sizeof (Elf32_Sym));
905 		gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf32_Sym);
906 	}
907 
908 	n = gst->gst_dsect->gs_shdr.sh_size /
909 	    gst->gst_dsect->gs_shdr.sh_entsize;
910 
911 	for (i = 0; i < n; i++, sym++) {
912 		const char *name = base + sym->st_name;
913 		uchar_t type = ELF32_ST_TYPE(sym->st_info);
914 
915 		if (type >= STT_NUM || type == STT_SECTION)
916 			continue; /* skip sections and unknown types */
917 
918 		if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') {
919 			if (sym->st_name >= ss_size || name[0] != '\0') {
920 				warn("ignoring %s symbol [%u]: invalid name\n",
921 				    gst->gst_dsect->gs_name, i);
922 				sym->st_name = 0;
923 			}
924 			continue; /* skip corrupt or empty names */
925 		}
926 
927 		(void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG);
928 
929 		if (sym->st_value != 0 &&
930 		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
931 			asrsv++; /* reserve space in the address map */
932 	}
933 
934 	if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
935 		GElf_Word smax = gst->gst_file->gf_shnum;
936 		mdb_gelf_sect_t *gsp;
937 
938 		for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
939 			if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) {
940 				gsp = &gst->gst_file->gf_sects[sym->st_shndx];
941 				sym->st_value += gsp->gs_shdr.sh_offset;
942 
943 				if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL ||
944 				    sym->st_size != 0)
945 					asrsv++; /* reserve space in asmap */
946 			}
947 		}
948 	}
949 
950 	gst->gst_asmap = mdb_alloc(sizeof (Elf32_Sym *) * asrsv, UM_SLEEP);
951 	gst->gst_asrsv = asrsv;
952 
953 	gelf32_symtab_sort(gst);
954 }
955 
956 static void
957 gelf64_symtab_sort(mdb_gelf_symtab_t *gst)
958 {
959 	Elf64_Sym **sympp = (Elf64_Sym **)gst->gst_asmap;
960 	mdb_var_t *v;
961 
962 	mdb_nv_rewind(&gst->gst_nv);
963 
964 	while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
965 		Elf64_Sym *sym = MDB_NV_COOKIE(v);
966 		if (sym->st_value != 0 &&
967 		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
968 			*sympp++ = sym;
969 	}
970 
971 	gst->gst_aslen = (size_t)(sympp - (Elf64_Sym **)gst->gst_asmap);
972 	ASSERT(gst->gst_aslen <= gst->gst_asrsv);
973 
974 	gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL;
975 
976 	qsort(gst->gst_asmap, gst->gst_aslen,
977 	    sizeof (Elf64_Sym *), gelf64_sym_compare);
978 
979 	gelf_strtab = NULL;
980 }
981 
982 static void
983 gelf64_symtab_init(mdb_gelf_symtab_t *gst)
984 {
985 	const char *base = (const char *)gst->gst_ssect->gs_data;
986 	Elf64_Sym *sym = gst->gst_dsect->gs_data;
987 	mdb_nv_t *nv = &gst->gst_nv;
988 
989 	Elf64_Xword ss_size = gst->gst_ssect->gs_shdr.sh_size;
990 	size_t asrsv = 0;
991 	GElf_Word i, n;
992 
993 	if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf64_Sym)) {
994 		warn("%s sh_entsize %llu != sizeof (Elf64_Sym); "
995 		    "using %u instead\n", gst->gst_dsect->gs_name,
996 		    (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize,
997 		    (uint_t)sizeof (Elf64_Sym));
998 		gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf64_Sym);
999 	}
1000 
1001 	n = gst->gst_dsect->gs_shdr.sh_size /
1002 	    gst->gst_dsect->gs_shdr.sh_entsize;
1003 
1004 	for (i = 0; i < n; i++, sym++) {
1005 		const char *name = base + sym->st_name;
1006 		uchar_t type = ELF64_ST_TYPE(sym->st_info);
1007 
1008 		if (type >= STT_NUM || type == STT_SECTION)
1009 			continue; /* skip sections and unknown types */
1010 
1011 		if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') {
1012 			if (sym->st_name >= ss_size || name[0] != '\0') {
1013 				warn("ignoring %s symbol [%u]: invalid name\n",
1014 				    gst->gst_dsect->gs_name, i);
1015 				sym->st_name = 0;
1016 			}
1017 			continue; /* skip corrupt or empty names */
1018 		}
1019 
1020 		(void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG);
1021 
1022 		if (sym->st_value != 0 &&
1023 		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
1024 			asrsv++; /* reserve space in the address map */
1025 	}
1026 
1027 	if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
1028 		GElf_Word smax = gst->gst_file->gf_shnum;
1029 		mdb_gelf_sect_t *gsp;
1030 
1031 		for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
1032 			if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) {
1033 				gsp = &gst->gst_file->gf_sects[sym->st_shndx];
1034 				sym->st_value += gsp->gs_shdr.sh_offset;
1035 
1036 				if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL ||
1037 				    sym->st_size != 0)
1038 					asrsv++; /* reserve space in asmap */
1039 			}
1040 		}
1041 	}
1042 
1043 	gst->gst_asmap = mdb_alloc(sizeof (Elf64_Sym *) * asrsv, UM_SLEEP);
1044 	gst->gst_asrsv = asrsv;
1045 
1046 	gelf64_symtab_sort(gst);
1047 }
1048 
1049 mdb_gelf_symtab_t *
1050 mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype,
1051     uint_t tabid)
1052 {
1053 	mdb_gelf_sect_t *gsp;
1054 	const char *dsname = NULL;
1055 	const char *ssname;
1056 	GElf_Half i;
1057 	GElf_Word link;
1058 
1059 	/*
1060 	 * Examine the sh_link field in the the Elf header to get the name
1061 	 * of the corresponding strings section
1062 	 */
1063 	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1064 		if (gsp->gs_shdr.sh_type == elftype) {
1065 			dsname = gsp->gs_name;
1066 			link = gsp->gs_shdr.sh_link;
1067 			break;
1068 		}
1069 	}
1070 
1071 	if (dsname == NULL)
1072 		return (NULL);
1073 
1074 	if (link > gf->gf_shnum) {
1075 		/*
1076 		 * Invalid link number due to corrupt elf file.
1077 		 */
1078 		warn("link number %ud larger than number of sections %d\n",
1079 		    link, gf->gf_shnum);
1080 		return (NULL);
1081 	}
1082 
1083 	ssname = (gf->gf_sects + link)->gs_name;
1084 
1085 	return (mdb_gelf_symtab_create_file_by_name(gf, dsname, ssname, tabid));
1086 }
1087 
1088 mdb_gelf_symtab_t *
1089 mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf,
1090     const char *dsname, const char *ssname, uint_t tabid)
1091 {
1092 	mdb_gelf_symtab_t *gst;
1093 	mdb_gelf_sect_t *gsp;
1094 	GElf_Half i;
1095 
1096 	gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1097 	(void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1098 
1099 	gst->gst_asmap = NULL;
1100 	gst->gst_aslen = 0;
1101 	gst->gst_asrsv = 0;
1102 	gst->gst_ehdr = &gf->gf_ehdr;
1103 	gst->gst_file = gf;
1104 	gst->gst_dsect = NULL;
1105 	gst->gst_ssect = NULL;
1106 	gst->gst_id = 0;
1107 	gst->gst_tabid = tabid;
1108 
1109 	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1110 		if (strcmp(gsp->gs_name, dsname) == 0) {
1111 			gst->gst_dsect = gsp;
1112 			break;
1113 		}
1114 	}
1115 
1116 	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
1117 		if (strcmp(gsp->gs_name, ssname) == 0) {
1118 			gst->gst_ssect = gsp;
1119 			break;
1120 		}
1121 	}
1122 
1123 	if (gst->gst_dsect == NULL || gst->gst_ssect == NULL)
1124 		goto err; /* Failed to locate data or string section */
1125 
1126 	if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL)
1127 		goto err; /* Failed to load data section */
1128 
1129 	if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL)
1130 		goto err; /* Failed to load string section */
1131 
1132 	if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32)
1133 		gelf32_symtab_init(gst);
1134 	else
1135 		gelf64_symtab_init(gst);
1136 
1137 	return (gst);
1138 
1139 err:
1140 	mdb_nv_destroy(&gst->gst_nv);
1141 	mdb_free(gst, sizeof (mdb_gelf_symtab_t));
1142 	return (NULL);
1143 }
1144 
1145 mdb_gelf_symtab_t *
1146 mdb_gelf_symtab_create_raw(const GElf_Ehdr *ehdr, const void *dshdr,
1147     void *ddata, const void *sshdr, void *sdata, uint_t tabid)
1148 {
1149 	mdb_gelf_symtab_t *gst;
1150 
1151 	gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1152 	(void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1153 
1154 	gst->gst_asmap = NULL;
1155 	gst->gst_aslen = 0;
1156 	gst->gst_asrsv = 0;
1157 	gst->gst_ehdr = ehdr;
1158 	gst->gst_file = NULL; /* Flag for raw symtab */
1159 	gst->gst_id = 0;
1160 	gst->gst_tabid = tabid;
1161 
1162 	gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1163 	gst->gst_dsect->gs_name = ".symtab";
1164 	gst->gst_dsect->gs_data = ddata;
1165 
1166 	gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1167 	gst->gst_ssect->gs_name = ".strtab";
1168 	gst->gst_ssect->gs_data = sdata;
1169 
1170 	if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1171 		(void) gelf32_to_shdr(dshdr, &gst->gst_dsect->gs_shdr);
1172 		(void) gelf32_to_shdr(sshdr, &gst->gst_ssect->gs_shdr);
1173 		gelf32_symtab_init(gst);
1174 	} else {
1175 		(void) gelf64_to_shdr(dshdr, &gst->gst_dsect->gs_shdr);
1176 		(void) gelf64_to_shdr(sshdr, &gst->gst_ssect->gs_shdr);
1177 		gelf64_symtab_init(gst);
1178 	}
1179 
1180 	return (gst);
1181 }
1182 
1183 mdb_gelf_symtab_t *
1184 mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t *gf, uint_t tabid)
1185 {
1186 	GElf_Addr dt_symtab, dt_strtab, dt_hash;
1187 	GElf_Xword dt_syment, dt_strsz;
1188 
1189 	mdb_gelf_symtab_t *gst;
1190 	uint_t hash_h[2];
1191 	off64_t base = 0;
1192 
1193 	ASSERT(gf->gf_mode == GF_PROGRAM);
1194 
1195 	/*
1196 	 * Read in and cache the array of GElf_Dyn structures from the
1197 	 * PT_DYNAMIC phdr.  Abort if this is not possible.
1198 	 */
1199 	if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1200 		(void) gelf_dyns_init(gf, sizeof (Elf32_Dyn),
1201 		    (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn);
1202 	} else {
1203 		(void) gelf_dyns_init(gf, sizeof (Elf64_Dyn),
1204 		    (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn);
1205 	}
1206 
1207 	/*
1208 	 * Pre-fetch all the DT_* entries we will need for creating the
1209 	 * dynamic symbol table; abort if any are missing.
1210 	 */
1211 	if ((dt_hash = gelf_dyn_lookup(gf, DT_HASH)) == -1L) {
1212 		warn("failed to get DT_HASH for %s\n", IOP_NAME(gf->gf_io));
1213 		return (NULL);
1214 	}
1215 
1216 	if ((dt_symtab = gelf_dyn_lookup(gf, DT_SYMTAB)) == -1L) {
1217 		warn("failed to get DT_SYMTAB for %s\n", IOP_NAME(gf->gf_io));
1218 		return (NULL);
1219 	}
1220 
1221 	if ((dt_syment = gelf_dyn_lookup(gf, DT_SYMENT)) == -1L) {
1222 		warn("failed to get DT_SYMENT for %s\n", IOP_NAME(gf->gf_io));
1223 		return (NULL);
1224 	}
1225 
1226 	if ((dt_strtab = gelf_dyn_lookup(gf, DT_STRTAB)) == -1L) {
1227 		warn("failed to get DT_STRTAB for %s\n", IOP_NAME(gf->gf_io));
1228 		return (NULL);
1229 	}
1230 
1231 	if ((dt_strsz = gelf_dyn_lookup(gf, DT_STRSZ)) == -1L) {
1232 		warn("failed to get DT_STRSZ for %s\n", IOP_NAME(gf->gf_io));
1233 		return (NULL);
1234 	}
1235 
1236 	/*
1237 	 * If this is an executable, then DT_HASH is an absolute address;
1238 	 * we need to subtract the virtual base address of the mapping.
1239 	 */
1240 	if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0)
1241 		base = (off64_t)gf->gf_phdrs->p_vaddr;
1242 
1243 	/*
1244 	 * Read in the header for the DT_HASH: this consists of nbucket
1245 	 * and nchain values (nchain is the number of hashed symbols).
1246 	 */
1247 	if (IOP_SEEK(gf->gf_io, (off64_t)dt_hash - base, SEEK_SET) == -1) {
1248 		warn("failed to seek ELF file to start of DT_HASH");
1249 		return (NULL);
1250 	}
1251 
1252 	if (IOP_READ(gf->gf_io, hash_h, sizeof (hash_h)) != sizeof (hash_h)) {
1253 		warn("failed to read DT_HASH header");
1254 		return (NULL);
1255 	}
1256 
1257 	gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1258 	(void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1259 
1260 	gst->gst_asmap = NULL;
1261 	gst->gst_aslen = 0;
1262 	gst->gst_asrsv = 0;
1263 	gst->gst_ehdr = &gf->gf_ehdr;
1264 	gst->gst_file = gf;
1265 	gst->gst_id = 0;
1266 	gst->gst_tabid = tabid;
1267 
1268 	gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1269 	gst->gst_dsect->gs_name = ".dynsym";
1270 	gst->gst_dsect->gs_shdr.sh_offset = dt_symtab - (GElf_Addr)base;
1271 	gst->gst_dsect->gs_shdr.sh_size = hash_h[1] * dt_syment;
1272 	gst->gst_dsect->gs_shdr.sh_entsize = dt_syment;
1273 
1274 	gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP);
1275 	gst->gst_ssect->gs_name = ".dynstr";
1276 	gst->gst_ssect->gs_shdr.sh_offset = dt_strtab - (GElf_Addr)base;
1277 	gst->gst_ssect->gs_shdr.sh_size = dt_strsz;
1278 	gst->gst_ssect->gs_shdr.sh_entsize = 0;
1279 
1280 	if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL)
1281 		goto err;
1282 
1283 	if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL)
1284 		goto err;
1285 
1286 	if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32)
1287 		gelf32_symtab_init(gst);
1288 	else
1289 		gelf64_symtab_init(gst);
1290 
1291 	return (gst);
1292 
1293 err:
1294 	mdb_gelf_symtab_destroy(gst);
1295 	return (NULL);
1296 }
1297 
1298 mdb_gelf_symtab_t *
1299 mdb_gelf_symtab_create_mutable(void)
1300 {
1301 	mdb_gelf_symtab_t *gst;
1302 	static GElf_Ehdr ehdr;
1303 
1304 	gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP);
1305 	(void) mdb_nv_create(&gst->gst_nv, UM_SLEEP);
1306 	gst->gst_ehdr = &ehdr;
1307 
1308 	if (ehdr.e_version == 0) {
1309 #ifdef	_LP64
1310 		uchar_t class = ELFCLASS64;
1311 #else
1312 		uchar_t class = ELFCLASS32;
1313 #endif
1314 
1315 #ifdef _BIG_ENDIAN
1316 		uchar_t data = ELFDATA2MSB;
1317 #else
1318 		uchar_t data = ELFDATA2LSB;
1319 #endif
1320 		/*
1321 		 * Since all mutable symbol tables will use a native Ehdr,
1322 		 * we can just have a single static copy which they all
1323 		 * point to and we only need initialize once.
1324 		 */
1325 		ehdr.e_ident[EI_MAG0] = ELFMAG0;
1326 		ehdr.e_ident[EI_MAG1] = ELFMAG1;
1327 		ehdr.e_ident[EI_MAG2] = ELFMAG2;
1328 		ehdr.e_ident[EI_MAG3] = ELFMAG3;
1329 		ehdr.e_ident[EI_CLASS] = class;
1330 		ehdr.e_ident[EI_DATA] = data;
1331 		ehdr.e_ident[EI_VERSION] = EV_CURRENT;
1332 		ehdr.e_type = ET_NONE;
1333 		ehdr.e_version = EV_CURRENT;
1334 	}
1335 
1336 	return (gst);
1337 }
1338 
1339 void
1340 mdb_gelf_symtab_destroy(mdb_gelf_symtab_t *gst)
1341 {
1342 	if (gst->gst_file == NULL) {
1343 		if (gst->gst_dsect == NULL && gst->gst_ssect == NULL) {
1344 			mdb_var_t *v;
1345 
1346 			mdb_nv_rewind(&gst->gst_nv);
1347 			while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
1348 				char *name = (char *)mdb_nv_get_name(v);
1349 				mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1350 
1351 				mdb_free(name, strlen(name) + 1);
1352 				mdb_free(dsp, sizeof (mdb_gelf_dsym_t));
1353 			}
1354 
1355 		} else {
1356 			mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t));
1357 			mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t));
1358 		}
1359 
1360 	} else if (gst->gst_file->gf_mode == GF_PROGRAM) {
1361 		mdb_gelf_sect_t *dsect = gst->gst_dsect;
1362 		mdb_gelf_sect_t *ssect = gst->gst_ssect;
1363 
1364 		if (dsect->gs_data != NULL)
1365 			mdb_free(dsect->gs_data, dsect->gs_shdr.sh_size);
1366 		if (ssect->gs_data != NULL)
1367 			mdb_free(ssect->gs_data, ssect->gs_shdr.sh_size);
1368 
1369 		mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t));
1370 		mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t));
1371 	}
1372 
1373 	mdb_nv_destroy(&gst->gst_nv);
1374 	mdb_free(gst->gst_asmap, gst->gst_asrsv * sizeof (void *));
1375 	mdb_free(gst, sizeof (mdb_gelf_symtab_t));
1376 }
1377 
1378 size_t
1379 mdb_gelf_symtab_size(mdb_gelf_symtab_t *gst)
1380 {
1381 	return (mdb_nv_size(&gst->gst_nv));
1382 }
1383 
1384 static GElf_Sym *
1385 gelf32_to_sym(const Elf32_Sym *src, GElf_Sym *dst)
1386 {
1387 	if (src != NULL) {
1388 		dst->st_name = src->st_name;
1389 		dst->st_info = src->st_info;
1390 		dst->st_other = src->st_other;
1391 		dst->st_shndx = src->st_shndx;
1392 		dst->st_value = src->st_value;
1393 		dst->st_size = src->st_size;
1394 		return (dst);
1395 	}
1396 
1397 	return (NULL);
1398 }
1399 
1400 static GElf_Sym *
1401 gelf64_to_sym(const Elf64_Sym *src, GElf_Sym *dst)
1402 {
1403 	if (src != NULL) {
1404 		bcopy(src, dst, sizeof (GElf_Sym));
1405 		return (dst);
1406 	}
1407 
1408 	return (NULL);
1409 }
1410 
1411 /*ARGSUSED*/
1412 static GElf_Sym *
1413 gelf64_nocopy(const Elf64_Sym *src, GElf_Sym *dst)
1414 {
1415 	return ((GElf_Sym *)src);
1416 }
1417 
1418 static const void *
1419 gelf32_sym_search(const Elf32_Sym **asmap, size_t aslen, uintptr_t addr)
1420 {
1421 	ulong_t i, mid, lo = 0, hi = aslen - 1;
1422 	const Elf32_Sym *symp;
1423 	Elf32_Addr v;
1424 	size_t size;
1425 
1426 	if (aslen == 0)
1427 		return (NULL);
1428 
1429 	while (hi - lo > 1) {
1430 		mid = (lo + hi) / 2;
1431 		if (addr >= asmap[mid]->st_value)
1432 			lo = mid;
1433 		else
1434 			hi = mid;
1435 	}
1436 
1437 	i = addr < asmap[hi]->st_value ? lo : hi;
1438 	symp = asmap[i];
1439 	v = symp->st_value;
1440 
1441 	/*
1442 	 * If the previous entry has the same value, improve our choice.  The
1443 	 * order of equal-valued symbols is determined by gelf32_sym_compare().
1444 	 */
1445 	while (i-- != 0 && asmap[i]->st_value == v)
1446 		symp = asmap[i];
1447 
1448 	/*
1449 	 * If an absolute symbol distance was specified, use that; otherwise
1450 	 * use the ELF symbol size, or 1 byte if the ELF size is zero.
1451 	 */
1452 	if (mdb.m_symdist == 0)
1453 		size = MAX(symp->st_size, 1);
1454 	else
1455 		size = mdb.m_symdist;
1456 
1457 	if (addr - symp->st_value < size)
1458 		return (symp);
1459 
1460 	return (NULL);
1461 }
1462 
1463 static const void *
1464 gelf64_sym_search(const Elf64_Sym **asmap, size_t aslen, uintptr_t addr)
1465 {
1466 	ulong_t i, mid, lo = 0, hi = aslen - 1;
1467 	const Elf64_Sym *symp;
1468 	Elf64_Addr v;
1469 	size_t size;
1470 
1471 	if (aslen == 0)
1472 		return (NULL);
1473 
1474 	while (hi - lo > 1) {
1475 		mid = (lo + hi) / 2;
1476 		if (addr >= asmap[mid]->st_value)
1477 			lo = mid;
1478 		else
1479 			hi = mid;
1480 	}
1481 
1482 	i = addr < asmap[hi]->st_value ? lo : hi;
1483 	symp = asmap[i];
1484 	v = symp->st_value;
1485 
1486 	/*
1487 	 * If the previous entry has the same value, improve our choice.  The
1488 	 * order of equal-valued symbols is determined by gelf64_sym_compare().
1489 	 */
1490 	while (i-- != 0 && asmap[i]->st_value == v)
1491 		symp = asmap[i];
1492 
1493 	/*
1494 	 * If an absolute symbol distance was specified, use that; otherwise
1495 	 * use the ELF symbol size, or 1 byte if the ELF size is zero.
1496 	 */
1497 	if (mdb.m_symdist == 0)
1498 		size = MAX(symp->st_size, 1);
1499 	else
1500 		size = mdb.m_symdist;
1501 
1502 	if (addr - symp->st_value < size)
1503 		return (symp);
1504 
1505 	return (NULL);
1506 }
1507 
1508 const char *
1509 mdb_gelf_sym_name(mdb_gelf_symtab_t *gst, const GElf_Sym *sym)
1510 {
1511 	const mdb_gelf_dsym_t *dsp;
1512 
1513 	if (gst->gst_ssect != NULL)
1514 		return ((const char *)gst->gst_ssect->gs_data + sym->st_name);
1515 
1516 	if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1517 		dsp = gelf32_sym_search(gst->gst_asmap,
1518 		    gst->gst_aslen, sym->st_value);
1519 	else
1520 		dsp = gelf64_sym_search(gst->gst_asmap,
1521 		    gst->gst_aslen, sym->st_value);
1522 
1523 	if (dsp != NULL)
1524 		return (mdb_nv_get_name(dsp->ds_var));
1525 
1526 	return (NULL);
1527 }
1528 
1529 int
1530 mdb_gelf_sym_closer(const GElf_Sym *s1, const GElf_Sym *s2, uintptr_t addr)
1531 {
1532 	uintptr_t v1 = (uintptr_t)s1->st_value;
1533 	uintptr_t v2 = (uintptr_t)s2->st_value;
1534 
1535 	uintptr_t d1 = v1 > addr ? v1 - addr : addr - v1;
1536 	uintptr_t d2 = v2 > addr ? v2 - addr : addr - v2;
1537 
1538 	return (d1 < d2);
1539 }
1540 
1541 int
1542 mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t *gst, uintptr_t addr,
1543     uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym, uint_t *idp)
1544 {
1545 	union {
1546 		const mdb_gelf_dsym_t *dsp;
1547 		const Elf32_Sym *s32;
1548 		const Elf64_Sym *s64;
1549 		caddr_t sp;
1550 	} u;
1551 
1552 	const char *name;
1553 
1554 	if (gst == NULL)
1555 		return (set_errno(EMDB_NOSYMADDR));
1556 
1557 	if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1558 		u.s32 = gelf32_sym_search(gst->gst_asmap, gst->gst_aslen, addr);
1559 		if (gelf32_to_sym(u.s32, sym) == NULL)
1560 			return (set_errno(EMDB_NOSYMADDR));
1561 	} else {
1562 		u.s64 = gelf64_sym_search(gst->gst_asmap, gst->gst_aslen, addr);
1563 		if (gelf64_to_sym(u.s64, sym) == NULL)
1564 			return (set_errno(EMDB_NOSYMADDR));
1565 	}
1566 
1567 	if ((flags & GST_EXACT) && (sym->st_value != addr))
1568 		return (set_errno(EMDB_NOSYMADDR));
1569 
1570 	if (gst->gst_ssect != NULL) {
1571 		name = (const char *)gst->gst_ssect->gs_data + sym->st_name;
1572 		if (idp != NULL) {
1573 			*idp = (u.sp - (caddr_t)gst->gst_dsect->gs_data) /
1574 			    gst->gst_dsect->gs_shdr.sh_entsize;
1575 		}
1576 	} else {
1577 		name = mdb_nv_get_name(u.dsp->ds_var);
1578 		if (idp != NULL)
1579 			*idp = u.dsp->ds_id;
1580 	}
1581 
1582 	if (nbytes > 0) {
1583 		(void) strncpy(buf, name, nbytes - 1);
1584 		buf[nbytes - 1] = '\0';
1585 	}
1586 	return (0);
1587 }
1588 
1589 int
1590 mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t *gst, const char *name,
1591     GElf_Sym *sym, uint_t *idp)
1592 {
1593 	mdb_var_t *v;
1594 
1595 	if (gst != NULL && (v = mdb_nv_lookup(&gst->gst_nv, name)) != NULL) {
1596 		if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1597 			(void) gelf32_to_sym(mdb_nv_get_cookie(v), sym);
1598 		else
1599 			(void) gelf64_to_sym(mdb_nv_get_cookie(v), sym);
1600 
1601 		if (idp != NULL) {
1602 			if (gst->gst_file == NULL && gst->gst_dsect == NULL) {
1603 				mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1604 				*idp = dsp->ds_id;
1605 			} else {
1606 				*idp = ((uintptr_t)mdb_nv_get_cookie(v) -
1607 				    (uintptr_t)gst->gst_dsect->gs_data) /
1608 				    gst->gst_dsect->gs_shdr.sh_entsize;
1609 			}
1610 		}
1611 
1612 		return (0);
1613 	}
1614 
1615 	return (set_errno(EMDB_NOSYM));
1616 }
1617 
1618 int
1619 mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t *gst, const char *file,
1620     const char *name, GElf_Sym *sym, uint_t *idp)
1621 {
1622 	GElf_Sym *(*s2gelf)(const void *, GElf_Sym *);
1623 	size_t sym_size;
1624 	caddr_t sp, ep;
1625 	mdb_var_t *v;
1626 
1627 	if (gst == NULL)
1628 		return (set_errno(EMDB_NOSYM));
1629 
1630 	if ((v = mdb_nv_lookup(&gst->gst_nv, file)) == NULL)
1631 		return (set_errno(EMDB_NOOBJ));
1632 
1633 	if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1634 		s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym;
1635 		sym_size = sizeof (Elf32_Sym);
1636 	} else {
1637 		s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_to_sym;
1638 		sym_size = sizeof (Elf64_Sym);
1639 	}
1640 
1641 	(void) s2gelf(mdb_nv_get_cookie(v), sym);
1642 
1643 	if (GELF_ST_TYPE(sym->st_info) != STT_FILE)
1644 		return (set_errno(EMDB_NOOBJ));
1645 
1646 	ep = (caddr_t)gst->gst_dsect->gs_data + gst->gst_dsect->gs_shdr.sh_size;
1647 	sp = (caddr_t)mdb_nv_get_cookie(v);
1648 
1649 	/*
1650 	 * We assume that symbol lookups scoped by source file name are only
1651 	 * relevant for userland debugging and are a relatively rare request,
1652 	 * and so we use a simple but inefficient linear search with copying.
1653 	 */
1654 	for (sp += sym_size; sp < ep; sp += sym_size) {
1655 		(void) s2gelf(sp, sym);	/* Convert native symbol to GElf */
1656 
1657 		if (GELF_ST_TYPE(sym->st_info) == STT_SECTION ||
1658 		    GELF_ST_TYPE(sym->st_info) == STT_FILE ||
1659 		    GELF_ST_BIND(sym->st_info) != STB_LOCAL)
1660 			break;		/* End of this file's locals */
1661 
1662 		if (strcmp(mdb_gelf_sym_name(gst, sym), name) == 0) {
1663 			if (idp != NULL) {
1664 				*idp = (sp - (caddr_t)
1665 				    gst->gst_dsect->gs_data) / sym_size;
1666 			}
1667 			return (0);
1668 		}
1669 	}
1670 
1671 	return (set_errno(EMDB_NOSYM));
1672 }
1673 
1674 void
1675 mdb_gelf_symtab_iter(mdb_gelf_symtab_t *gst, int (*func)(void *,
1676     const GElf_Sym *, const char *, uint_t), void *private)
1677 {
1678 	GElf_Sym *(*s2gelf)(const void *, GElf_Sym *);
1679 	GElf_Sym sym, *symp;
1680 	size_t sym_size;
1681 
1682 	if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1683 		s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym;
1684 		sym_size = sizeof (Elf32_Sym);
1685 	} else {
1686 		s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_nocopy;
1687 		sym_size = sizeof (Elf64_Sym);
1688 	}
1689 
1690 	/*
1691 	 * If this is a mutable symbol table, we iterate over the hash table
1692 	 * of symbol names; otherwise we go iterate over the data buffer.  For
1693 	 * non-mutable tables, this means that ::nm will show all symbols,
1694 	 * including those with duplicate names (not present in gst_nv).
1695 	 */
1696 	if (gst->gst_file == NULL && gst->gst_dsect == NULL) {
1697 		mdb_gelf_dsym_t *dsp;
1698 		mdb_var_t *v;
1699 
1700 		mdb_nv_rewind(&gst->gst_nv);
1701 		while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) {
1702 			dsp = mdb_nv_get_cookie(v);
1703 			symp = s2gelf(dsp, &sym);
1704 			if (func(private, symp, mdb_nv_get_name(v),
1705 			    dsp->ds_id) == -1)
1706 				break;
1707 		}
1708 
1709 	} else {
1710 		const char *sbase = gst->gst_ssect->gs_data;
1711 		caddr_t sp = gst->gst_dsect->gs_data;
1712 		caddr_t ep = sp + gst->gst_dsect->gs_shdr.sh_size;
1713 		uint_t i;
1714 
1715 		for (i = 0; sp < ep; sp += sym_size, i++) {
1716 			symp = s2gelf(sp, &sym);
1717 			if (func(private, symp, sbase + symp->st_name, i) == -1)
1718 				break;
1719 		}
1720 	}
1721 }
1722 
1723 static void
1724 gelf_sym_to_32(const GElf_Sym *src, Elf32_Sym *dst)
1725 {
1726 	dst->st_name = src->st_name;
1727 	dst->st_info = src->st_info;
1728 	dst->st_other = src->st_other;
1729 	dst->st_shndx = src->st_shndx;
1730 	dst->st_value = (Elf32_Addr)src->st_value;
1731 	dst->st_size = (Elf32_Word)src->st_size;
1732 }
1733 
1734 static void
1735 gelf_sym_to_64(const GElf_Sym *src, Elf64_Sym *dst)
1736 {
1737 	bcopy(src, dst, sizeof (Elf64_Sym));
1738 }
1739 
1740 void
1741 mdb_gelf_symtab_insert(mdb_gelf_symtab_t *gst,
1742     const char *name, const GElf_Sym *symp)
1743 {
1744 	mdb_gelf_dsym_t *dsp;
1745 	mdb_var_t *v;
1746 
1747 	ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL);
1748 	v = mdb_nv_lookup(&gst->gst_nv, name);
1749 
1750 	if (v == NULL) {
1751 		char *s = mdb_alloc(strlen(name) + 1, UM_SLEEP);
1752 		(void) strcpy(s, name);
1753 
1754 		dsp = mdb_alloc(sizeof (mdb_gelf_dsym_t), UM_SLEEP);
1755 		dsp->ds_id = gst->gst_id++;
1756 
1757 		dsp->ds_var = mdb_nv_insert(&gst->gst_nv, s, NULL,
1758 		    (uintptr_t)dsp, GST_NVFLG);
1759 
1760 		gst->gst_aslen++;
1761 		ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv));
1762 
1763 		if (gst->gst_aslen > gst->gst_asrsv) {
1764 			mdb_free(gst->gst_asmap,
1765 			    sizeof (void *) * gst->gst_asrsv);
1766 
1767 			gst->gst_asrsv = gst->gst_asrsv != 0 ?
1768 			    gst->gst_asrsv * GST_GROW : GST_DEFSZ;
1769 
1770 			gst->gst_asmap = mdb_alloc(sizeof (void *) *
1771 			    gst->gst_asrsv, UM_SLEEP);
1772 		}
1773 	} else
1774 		dsp = mdb_nv_get_cookie(v);
1775 
1776 	mdb_dprintf(MDB_DBG_ELF, "added symbol (\"%s\", %llx)\n",
1777 	    name, (u_longlong_t)symp->st_value);
1778 
1779 	bcopy(symp, &dsp->ds_sym, sizeof (GElf_Sym));
1780 	dsp->ds_sym.st_name = (uintptr_t)mdb_nv_get_name(dsp->ds_var);
1781 
1782 	if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
1783 		gelf_sym_to_32(symp, &dsp->ds_u.ds_s32);
1784 		gelf32_symtab_sort(gst);
1785 	} else {
1786 		gelf_sym_to_64(symp, &dsp->ds_u.ds_s64);
1787 		gelf64_symtab_sort(gst);
1788 	}
1789 }
1790 
1791 void
1792 mdb_gelf_symtab_delete(mdb_gelf_symtab_t *gst,
1793     const char *name, GElf_Sym *symp)
1794 {
1795 	mdb_var_t *v;
1796 
1797 	ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL);
1798 	v = mdb_nv_lookup(&gst->gst_nv, name);
1799 
1800 	if (v != NULL) {
1801 		char *name = (char *)mdb_nv_get_name(v);
1802 		mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v);
1803 
1804 		if (symp != NULL)
1805 			bcopy(&dsp->ds_sym, symp, sizeof (GElf_Sym));
1806 
1807 		mdb_dprintf(MDB_DBG_ELF, "removed symbol (\"%s\", %llx)\n",
1808 		    name, (u_longlong_t)dsp->ds_sym.st_value);
1809 
1810 		mdb_nv_remove(&gst->gst_nv, v);
1811 		gst->gst_aslen--;
1812 		ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv));
1813 
1814 		mdb_free(name, strlen(name) + 1);
1815 		mdb_free(dsp, sizeof (mdb_gelf_dsym_t));
1816 
1817 		if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
1818 			gelf32_symtab_sort(gst);
1819 		else
1820 			gelf64_symtab_sort(gst);
1821 	}
1822 }
1823 
1824 static const GElf_Phdr *
1825 gelf_phdr_lookup(mdb_gelf_file_t *gf, uintptr_t addr)
1826 {
1827 	const GElf_Phdr *gpp = gf->gf_phdrs;
1828 	GElf_Half i;
1829 
1830 	for (i = 0; i < gf->gf_npload; i++, gpp++) {
1831 		if (addr >= gpp->p_vaddr && addr < gpp->p_vaddr + gpp->p_memsz)
1832 			return (gpp);
1833 	}
1834 
1835 	return (NULL);
1836 }
1837 
1838 ssize_t
1839 mdb_gelf_rw(mdb_gelf_file_t *gf, void *buf, size_t nbytes, uintptr_t addr,
1840     ssize_t (*prw)(mdb_io_t *, void *, size_t), mdb_gelf_rw_t rw)
1841 {
1842 	ssize_t resid = nbytes;
1843 
1844 	while (resid != 0) {
1845 		const GElf_Phdr *php = gelf_phdr_lookup(gf, addr);
1846 
1847 		uintptr_t mapoff;
1848 		ssize_t memlen, filelen, len = 0;
1849 		off64_t off;
1850 
1851 		if (php == NULL)
1852 			break; /* No mapping for this address */
1853 
1854 		mapoff = addr - php->p_vaddr;
1855 		memlen = MIN(resid, php->p_memsz - mapoff);
1856 		filelen = MIN(resid, php->p_filesz - mapoff);
1857 		off = (off64_t)php->p_offset + mapoff;
1858 
1859 		if (filelen > 0 && (IOP_SEEK(gf->gf_io, off, SEEK_SET) != off ||
1860 		    (len = prw(gf->gf_io, buf, filelen)) <= 0))
1861 			break;
1862 
1863 		if (rw == GIO_READ && len == filelen && filelen < memlen) {
1864 			bzero((char *)buf + len, memlen - filelen);
1865 			len += memlen - filelen;
1866 		}
1867 
1868 		resid -= len;
1869 		addr += len;
1870 		buf = (char *)buf + len;
1871 	}
1872 
1873 	if (resid == nbytes && nbytes != 0)
1874 		return (set_errno(EMDB_NOMAP));
1875 
1876 	return (nbytes - resid);
1877 }
1878 
1879 mdb_gelf_sect_t *
1880 mdb_gelf_sect_by_name(mdb_gelf_file_t *gf, const char *name)
1881 {
1882 	int i;
1883 
1884 	for (i = 0; i < gf->gf_shnum; i++) {
1885 		if (strcmp(gf->gf_sects[i].gs_name, name) == 0)
1886 			return (&gf->gf_sects[i]);
1887 	}
1888 
1889 	return (NULL);
1890 }
1891