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