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