17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*a576ab5bSrab * Common Development and Distribution License (the "License"). 6*a576ab5bSrab * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*a576ab5bSrab * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 297c478bd9Sstevel@tonic-gate #include <sys/link.h> 307c478bd9Sstevel@tonic-gate #include <strings.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 347c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 357c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 367c478bd9Sstevel@tonic-gate #include <mdb/mdb_gelf.h> 377c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 387c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #define GST_GROW 2 /* Mutable symbol table growth multiplier */ 417c478bd9Sstevel@tonic-gate #define GST_DEFSZ 16 /* Mutable symbol table initial size */ 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #define GST_NVFLG (MDB_NV_EXTNAME | MDB_NV_SILENT) 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate static const char *gelf_strtab; /* Active string table for qsort callbacks */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 487c478bd9Sstevel@tonic-gate gelf_sect_init(mdb_gelf_file_t *gf) 497c478bd9Sstevel@tonic-gate { 5030da1432Sahl mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_shstrndx]; 517c478bd9Sstevel@tonic-gate GElf_Half i, npbit = 0; 527c478bd9Sstevel@tonic-gate GElf_Shdr *shp; 537c478bd9Sstevel@tonic-gate GElf_Phdr *gpp; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate if (gf->gf_mode == GF_PROGRAM) 5630da1432Sahl gf->gf_shnum = 0; /* Simplifies other code paths */ 577c478bd9Sstevel@tonic-gate 5830da1432Sahl if (gf->gf_shnum == 0) 597c478bd9Sstevel@tonic-gate return (gf); /* If no section headers we're done here */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, shstr->gs_shdr.sh_offset, SEEK_SET) == -1) { 627c478bd9Sstevel@tonic-gate warn("failed to seek %s to shdr strings", IOP_NAME(gf->gf_io)); 637c478bd9Sstevel@tonic-gate return (NULL); 647c478bd9Sstevel@tonic-gate } 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate shstr->gs_data = mdb_zalloc(shstr->gs_shdr.sh_size + 1, UM_SLEEP); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate if (IOP_READ(gf->gf_io, shstr->gs_data, shstr->gs_shdr.sh_size) != 697c478bd9Sstevel@tonic-gate shstr->gs_shdr.sh_size) { 707c478bd9Sstevel@tonic-gate warn("failed to read %s shdr strings", IOP_NAME(gf->gf_io)); 717c478bd9Sstevel@tonic-gate mdb_free(shstr->gs_data, shstr->gs_shdr.sh_size); 727c478bd9Sstevel@tonic-gate return (NULL); 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate 7530da1432Sahl for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 767c478bd9Sstevel@tonic-gate shp = &gsp->gs_shdr; 777c478bd9Sstevel@tonic-gate gsp->gs_name = (const char *)shstr->gs_data + shp->sh_name; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate if (shp->sh_name >= shstr->gs_shdr.sh_size) { 807c478bd9Sstevel@tonic-gate warn("section name for %s:[%u] is corrupt: %u\n", 817c478bd9Sstevel@tonic-gate IOP_NAME(gf->gf_io), (uint_t)i, shp->sh_name); 827c478bd9Sstevel@tonic-gate gsp->gs_name = shstr->gs_data; /* empty string */ 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate if (shp->sh_type == SHT_PROGBITS && (shp->sh_flags & SHF_ALLOC)) 867c478bd9Sstevel@tonic-gate npbit++; /* Keep count for ET_REL code below */ 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * If the file is of type ET_REL, we would still like to provide file 917c478bd9Sstevel@tonic-gate * i/o using the mdb_gelf_rw() function defined below. To simplify 927c478bd9Sstevel@tonic-gate * things, we forge up a sequence of Phdrs based on Shdrs which have 937c478bd9Sstevel@tonic-gate * been marked SHF_ALLOC and are of type SHT_PROGBITS. We convert 947c478bd9Sstevel@tonic-gate * relevant Shdr fields to their Phdr equivalents, and then set the 957c478bd9Sstevel@tonic-gate * p_vaddr (virtual base address) to the section's file offset. 967c478bd9Sstevel@tonic-gate * This allows us to relocate a given symbol by simply incrementing 977c478bd9Sstevel@tonic-gate * its st_value by the file offset of the section corresponding to 987c478bd9Sstevel@tonic-gate * its st_shndx, and then perform i/o to read or write the symbol's 997c478bd9Sstevel@tonic-gate * value in the object file. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_type == ET_REL && npbit != 0) { 1027c478bd9Sstevel@tonic-gate gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * npbit, UM_SLEEP); 10330da1432Sahl gf->gf_phnum = npbit; 1047c478bd9Sstevel@tonic-gate gf->gf_npload = npbit; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate gpp = gf->gf_phdrs; 1077c478bd9Sstevel@tonic-gate gsp = gf->gf_sects; 1087c478bd9Sstevel@tonic-gate 10930da1432Sahl for (i = 0; i < gf->gf_shnum; i++, gsp++) { 1107c478bd9Sstevel@tonic-gate shp = &gsp->gs_shdr; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate if ((shp->sh_type == SHT_PROGBITS) && 1137c478bd9Sstevel@tonic-gate (shp->sh_flags & SHF_ALLOC)) { 1147c478bd9Sstevel@tonic-gate gpp->p_type = PT_LOAD; 1157c478bd9Sstevel@tonic-gate gpp->p_flags = PF_R; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate if (shp->sh_flags & SHF_EXECINSTR) 1187c478bd9Sstevel@tonic-gate gpp->p_flags |= PF_X; 1197c478bd9Sstevel@tonic-gate if (shp->sh_flags & SHF_WRITE) 1207c478bd9Sstevel@tonic-gate gpp->p_flags |= PF_W; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate gpp->p_offset = shp->sh_offset; 1237c478bd9Sstevel@tonic-gate gpp->p_vaddr = shp->sh_offset; 1247c478bd9Sstevel@tonic-gate gpp->p_filesz = shp->sh_size; 1257c478bd9Sstevel@tonic-gate gpp->p_memsz = shp->sh_size; 1267c478bd9Sstevel@tonic-gate gpp->p_align = shp->sh_addralign; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate gpp++; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate return (gf); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 136*a576ab5bSrab void * 137*a576ab5bSrab mdb_gelf_sect_load(mdb_gelf_file_t *gf, mdb_gelf_sect_t *gsp) 1387c478bd9Sstevel@tonic-gate { 1397c478bd9Sstevel@tonic-gate ssize_t nbytes; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate if (gsp->gs_data != NULL) 1427c478bd9Sstevel@tonic-gate return (gsp->gs_data); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "loading %s:%s (%lu bytes)\n", 1457c478bd9Sstevel@tonic-gate IOP_NAME(gf->gf_io), gsp->gs_name, (ulong_t)gsp->gs_shdr.sh_size); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate gsp->gs_data = mdb_alloc(gsp->gs_shdr.sh_size, UM_SLEEP); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, gsp->gs_shdr.sh_offset, SEEK_SET) == -1) { 1507c478bd9Sstevel@tonic-gate warn("failed to seek to start of %s:%s", 1517c478bd9Sstevel@tonic-gate IOP_NAME(gf->gf_io), gsp->gs_name); 1527c478bd9Sstevel@tonic-gate goto err; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate nbytes = IOP_READ(gf->gf_io, gsp->gs_data, gsp->gs_shdr.sh_size); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (nbytes < 0) { 1587c478bd9Sstevel@tonic-gate warn("failed to read %s:%s", IOP_NAME(gf->gf_io), gsp->gs_name); 1597c478bd9Sstevel@tonic-gate goto err; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate if (nbytes < gsp->gs_shdr.sh_size) { 1637c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "only %ld of %llu bytes of %s:%s " 1647c478bd9Sstevel@tonic-gate "could be read\n", (long)nbytes, (u_longlong_t) 1657c478bd9Sstevel@tonic-gate gsp->gs_shdr.sh_size, IOP_NAME(gf->gf_io), gsp->gs_name); 1667c478bd9Sstevel@tonic-gate bzero((char *)gsp->gs_data + nbytes, 1677c478bd9Sstevel@tonic-gate (size_t)gsp->gs_shdr.sh_size - nbytes); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate return (gsp->gs_data); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate err: 1737c478bd9Sstevel@tonic-gate mdb_free(gsp->gs_data, sizeof (gsp->gs_shdr.sh_size)); 1747c478bd9Sstevel@tonic-gate gsp->gs_data = NULL; 1757c478bd9Sstevel@tonic-gate return (NULL); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate void 1797c478bd9Sstevel@tonic-gate mdb_gelf_ehdr_to_gehdr(Ehdr *src, GElf_Ehdr *dst) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate bcopy(src->e_ident, dst->e_ident, sizeof (dst->e_ident)); 1827c478bd9Sstevel@tonic-gate dst->e_type = src->e_type; 1837c478bd9Sstevel@tonic-gate dst->e_machine = src->e_machine; 1847c478bd9Sstevel@tonic-gate dst->e_version = src->e_version; 1857c478bd9Sstevel@tonic-gate dst->e_entry = src->e_entry; 1867c478bd9Sstevel@tonic-gate dst->e_phoff = src->e_phoff; 1877c478bd9Sstevel@tonic-gate dst->e_shoff = src->e_shoff; 1887c478bd9Sstevel@tonic-gate dst->e_flags = src->e_flags; 1897c478bd9Sstevel@tonic-gate dst->e_ehsize = src->e_ehsize; 1907c478bd9Sstevel@tonic-gate dst->e_phentsize = src->e_phentsize; 1917c478bd9Sstevel@tonic-gate dst->e_phnum = src->e_phnum; 1927c478bd9Sstevel@tonic-gate dst->e_shentsize = src->e_shentsize; 1937c478bd9Sstevel@tonic-gate dst->e_shnum = src->e_shnum; 1947c478bd9Sstevel@tonic-gate dst->e_shstrndx = src->e_shstrndx; 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static GElf_Shdr * 1987c478bd9Sstevel@tonic-gate gelf32_to_shdr(const Elf32_Shdr *src, GElf_Shdr *dst) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate if (src != NULL) { 2017c478bd9Sstevel@tonic-gate dst->sh_name = src->sh_name; 2027c478bd9Sstevel@tonic-gate dst->sh_type = src->sh_type; 2037c478bd9Sstevel@tonic-gate dst->sh_flags = src->sh_flags; 2047c478bd9Sstevel@tonic-gate dst->sh_addr = src->sh_addr; 2057c478bd9Sstevel@tonic-gate dst->sh_offset = src->sh_offset; 2067c478bd9Sstevel@tonic-gate dst->sh_size = src->sh_size; 2077c478bd9Sstevel@tonic-gate dst->sh_link = src->sh_link; 2087c478bd9Sstevel@tonic-gate dst->sh_info = src->sh_info; 2097c478bd9Sstevel@tonic-gate dst->sh_addralign = src->sh_addralign; 2107c478bd9Sstevel@tonic-gate dst->sh_entsize = src->sh_entsize; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate return (dst); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate return (NULL); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate static GElf_Shdr * 2197c478bd9Sstevel@tonic-gate gelf64_to_shdr(const Elf64_Shdr *src, GElf_Shdr *dst) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate if (src != NULL) { 2227c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (Elf64_Shdr)); 2237c478bd9Sstevel@tonic-gate return (dst); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate return (NULL); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 2307c478bd9Sstevel@tonic-gate gelf_shdrs_init(mdb_gelf_file_t *gf, size_t shdr_size, 2317c478bd9Sstevel@tonic-gate GElf_Shdr *(*elf2gelf)(const void *, GElf_Shdr *)) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate caddr_t shdrs, shp; 2347c478bd9Sstevel@tonic-gate GElf_Half i; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 2377c478bd9Sstevel@tonic-gate size_t nbytes; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "loading %s section headers (%hu entries)\n", 24030da1432Sahl IOP_NAME(gf->gf_io), gf->gf_shnum); 2417c478bd9Sstevel@tonic-gate 24230da1432Sahl if (gf->gf_shnum == 0) 2437c478bd9Sstevel@tonic-gate return (gf); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_shoff, SEEK_SET) == -1) { 2467c478bd9Sstevel@tonic-gate warn("failed to seek %s to shdrs", IOP_NAME(gf->gf_io)); 2477c478bd9Sstevel@tonic-gate return (NULL); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 25030da1432Sahl nbytes = shdr_size * gf->gf_shnum; 2517c478bd9Sstevel@tonic-gate shdrs = mdb_alloc(nbytes, UM_SLEEP); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if (IOP_READ(gf->gf_io, shdrs, nbytes) != nbytes) { 2547c478bd9Sstevel@tonic-gate warn("failed to read %s section headers", IOP_NAME(gf->gf_io)); 2557c478bd9Sstevel@tonic-gate mdb_free(shdrs, nbytes); 2567c478bd9Sstevel@tonic-gate return (NULL); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 25930da1432Sahl gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) * gf->gf_shnum, 26030da1432Sahl UM_SLEEP); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate shp = shdrs; 2637c478bd9Sstevel@tonic-gate gsp = gf->gf_sects; 2647c478bd9Sstevel@tonic-gate 26530da1432Sahl for (i = 0; i < gf->gf_shnum; i++, shp += shdr_size, gsp++) 2667c478bd9Sstevel@tonic-gate (void) elf2gelf(shp, &gsp->gs_shdr); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate mdb_free(shdrs, nbytes); 2697c478bd9Sstevel@tonic-gate return (gf); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate static GElf_Phdr * 2737c478bd9Sstevel@tonic-gate gelf32_to_phdr(const Elf32_Phdr *src, GElf_Phdr *dst) 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate if (src != NULL) { 2767c478bd9Sstevel@tonic-gate dst->p_type = src->p_type; 2777c478bd9Sstevel@tonic-gate dst->p_offset = src->p_offset; 2787c478bd9Sstevel@tonic-gate dst->p_vaddr = src->p_vaddr; 2797c478bd9Sstevel@tonic-gate dst->p_paddr = src->p_paddr; 2807c478bd9Sstevel@tonic-gate dst->p_filesz = src->p_filesz; 2817c478bd9Sstevel@tonic-gate dst->p_memsz = src->p_memsz; 2827c478bd9Sstevel@tonic-gate dst->p_flags = src->p_flags; 2837c478bd9Sstevel@tonic-gate dst->p_align = src->p_align; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate return (dst); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate return (NULL); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate static GElf_Phdr * 2927c478bd9Sstevel@tonic-gate gelf64_to_phdr(const Elf64_Phdr *src, GElf_Phdr *dst) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate if (src != NULL) { 2957c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (Elf64_Phdr)); 2967c478bd9Sstevel@tonic-gate return (dst); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate return (NULL); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static int 3037c478bd9Sstevel@tonic-gate gelf_phdr_compare(const void *lp, const void *rp) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate GElf_Phdr *lhs = (GElf_Phdr *)lp; 3067c478bd9Sstevel@tonic-gate GElf_Phdr *rhs = (GElf_Phdr *)rp; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * If both p_type fields are PT_LOAD, we want to sort by vaddr. 3107c478bd9Sstevel@tonic-gate * Exception is that p_vaddr == 0 means ignore this (put at end). 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate if (lhs->p_type == PT_LOAD && rhs->p_type == PT_LOAD) { 3137c478bd9Sstevel@tonic-gate if (lhs->p_vaddr != rhs->p_vaddr) { 3147c478bd9Sstevel@tonic-gate if (lhs->p_vaddr == 0) 3157c478bd9Sstevel@tonic-gate return (1); /* lhs is "greater" */ 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (rhs->p_vaddr == 0) 3187c478bd9Sstevel@tonic-gate return (-1); /* rhs is "greater" */ 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate return (lhs->p_vaddr > rhs->p_vaddr ? 1 : -1); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate return (0); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * If the p_type fields don't match, we need to make sure that PT_LOAD 3287c478bd9Sstevel@tonic-gate * entries are considered "less" (i.e. move towards the beginning 3297c478bd9Sstevel@tonic-gate * of the array we are sorting) 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate if (lhs->p_type != rhs->p_type) { 3327c478bd9Sstevel@tonic-gate if (lhs->p_type == PT_LOAD) 3337c478bd9Sstevel@tonic-gate return (-1); /* rhs is "greater" */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (rhs->p_type == PT_LOAD) 3367c478bd9Sstevel@tonic-gate return (1); /* lhs is "greater" */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate return (lhs->p_type > rhs->p_type ? 1 : -1); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * If the p_type is the same but neither is PT_LOAD, then 3437c478bd9Sstevel@tonic-gate * just sort by file offset (doesn't really matter) 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate if (lhs->p_offset != rhs->p_offset) 3467c478bd9Sstevel@tonic-gate return (lhs->p_offset > rhs->p_offset ? 1 : -1); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate return (0); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 3527c478bd9Sstevel@tonic-gate gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size, 3537c478bd9Sstevel@tonic-gate GElf_Phdr *(*elf2gelf)(const void *, GElf_Phdr *)) 3547c478bd9Sstevel@tonic-gate { 3557c478bd9Sstevel@tonic-gate caddr_t phdrs, php; 3567c478bd9Sstevel@tonic-gate GElf_Half i; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate GElf_Phdr *gpp; 3597c478bd9Sstevel@tonic-gate size_t nbytes; 3607c478bd9Sstevel@tonic-gate 36130da1432Sahl mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%lu entries)\n", 36230da1432Sahl IOP_NAME(gf->gf_io), gf->gf_phnum); 3637c478bd9Sstevel@tonic-gate 36430da1432Sahl if (gf->gf_phnum == 0) 3657c478bd9Sstevel@tonic-gate return (gf); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_phoff, SEEK_SET) == -1) { 3687c478bd9Sstevel@tonic-gate warn("failed to seek %s to phdrs", IOP_NAME(gf->gf_io)); 3697c478bd9Sstevel@tonic-gate return (NULL); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 37230da1432Sahl nbytes = phdr_size * gf->gf_phnum; 3737c478bd9Sstevel@tonic-gate phdrs = mdb_alloc(nbytes, UM_SLEEP); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate if (IOP_READ(gf->gf_io, phdrs, nbytes) != nbytes) { 3767c478bd9Sstevel@tonic-gate warn("failed to read %s program headers", IOP_NAME(gf->gf_io)); 3777c478bd9Sstevel@tonic-gate mdb_free(phdrs, nbytes); 3787c478bd9Sstevel@tonic-gate return (NULL); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 38130da1432Sahl gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * gf->gf_phnum, UM_SLEEP); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate php = phdrs; 3847c478bd9Sstevel@tonic-gate gpp = gf->gf_phdrs; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Iterate through the list of phdrs locating those that are of type 3887c478bd9Sstevel@tonic-gate * PT_LOAD; increment gf_npload so we know how many are loadable. 3897c478bd9Sstevel@tonic-gate */ 39030da1432Sahl for (i = 0; i < gf->gf_phnum; i++, php += phdr_size, gpp++) { 3917c478bd9Sstevel@tonic-gate (void) elf2gelf(php, gpp); 3927c478bd9Sstevel@tonic-gate if (gpp->p_type != PT_LOAD) 3937c478bd9Sstevel@tonic-gate continue; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "PT_LOAD va=0x%llx flags=0x%x " 3967c478bd9Sstevel@tonic-gate "memsz=%llu filesz=%llu off=%llu\n", (u_longlong_t) 3977c478bd9Sstevel@tonic-gate gpp->p_vaddr, gpp->p_flags, (u_longlong_t)gpp->p_memsz, 3987c478bd9Sstevel@tonic-gate (u_longlong_t)gpp->p_filesz, (u_longlong_t)gpp->p_offset); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate gf->gf_npload++; 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Now we sort the phdrs array using a comparison routine which 4057c478bd9Sstevel@tonic-gate * arranges for the PT_LOAD phdrs with non-zero virtual addresses 4067c478bd9Sstevel@tonic-gate * to come first sorted by virtual address. This means that we 4077c478bd9Sstevel@tonic-gate * can access the complete phdr table by examining the array 40830da1432Sahl * gf->gf_phdrs[0 .. gf->gf_phnum - 1], and we can access a sorted 40930da1432Sahl * array of valid PT_LOAD pdhrs by examining the array 4107c478bd9Sstevel@tonic-gate * gf->gf_phdrs[0 .. gf->gf_npload - 1]. 4117c478bd9Sstevel@tonic-gate */ 41230da1432Sahl qsort(gf->gf_phdrs, gf->gf_phnum, sizeof (GElf_Phdr), 4137c478bd9Sstevel@tonic-gate gelf_phdr_compare); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * Locate the PT_DYNAMIC Phdr if one is present; we save this 4177c478bd9Sstevel@tonic-gate * Phdr pointer in gf->gf_dynp for future use. 4187c478bd9Sstevel@tonic-gate */ 41930da1432Sahl for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_phnum; i++, gpp++) { 4207c478bd9Sstevel@tonic-gate if (gpp->p_type == PT_DYNAMIC) { 4217c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "PT_DYNAMIC " 4227c478bd9Sstevel@tonic-gate "filesize = %lluULL off=%lluULL\n", 4237c478bd9Sstevel@tonic-gate (u_longlong_t)gpp->p_filesz, 4247c478bd9Sstevel@tonic-gate (u_longlong_t)gpp->p_offset); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate gf->gf_dynp = gpp; 4277c478bd9Sstevel@tonic-gate break; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate mdb_free(phdrs, nbytes); 4327c478bd9Sstevel@tonic-gate return (gf); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate static GElf_Dyn * 4367c478bd9Sstevel@tonic-gate gelf32_to_dyn(const Elf32_Dyn *src, GElf_Dyn *dst) 4377c478bd9Sstevel@tonic-gate { 4387c478bd9Sstevel@tonic-gate if (src != NULL) { 4397c478bd9Sstevel@tonic-gate dst->d_tag = (GElf_Xword)(Elf32_Word)src->d_tag; 4407c478bd9Sstevel@tonic-gate dst->d_un.d_ptr = src->d_un.d_ptr; 4417c478bd9Sstevel@tonic-gate return (dst); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate return (NULL); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate static GElf_Dyn * 4487c478bd9Sstevel@tonic-gate gelf64_to_dyn(const Elf64_Dyn *src, GElf_Dyn *dst) 4497c478bd9Sstevel@tonic-gate { 4507c478bd9Sstevel@tonic-gate if (src != NULL) { 4517c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (Elf64_Dyn)); 4527c478bd9Sstevel@tonic-gate return (dst); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate return (NULL); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate static GElf_Xword 4597c478bd9Sstevel@tonic-gate gelf_dyn_lookup(mdb_gelf_file_t *gf, GElf_Xword tag) 4607c478bd9Sstevel@tonic-gate { 4617c478bd9Sstevel@tonic-gate size_t i; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate for (i = 0; i < gf->gf_ndyns; i++) { 4647c478bd9Sstevel@tonic-gate if (gf->gf_dyns[i].d_tag == tag) 4657c478bd9Sstevel@tonic-gate return (gf->gf_dyns[i].d_un.d_val); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate return ((GElf_Xword)-1L); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate static GElf_Dyn * 4727c478bd9Sstevel@tonic-gate gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size, 4737c478bd9Sstevel@tonic-gate GElf_Dyn *(*elf2gelf)(const void *, GElf_Dyn *)) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate size_t nbytes, ndyns, i; 4767c478bd9Sstevel@tonic-gate caddr_t dyns, dp; 4777c478bd9Sstevel@tonic-gate GElf_Dyn *gdp; 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate off64_t dyn_addr; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if (gf->gf_dyns != NULL) 4827c478bd9Sstevel@tonic-gate return (gf->gf_dyns); /* Already loaded */ 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate if (gf->gf_dynp == NULL) 4857c478bd9Sstevel@tonic-gate return (NULL); /* No PT_DYNAMIC entry was found */ 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate nbytes = gf->gf_dynp->p_filesz; 4887c478bd9Sstevel@tonic-gate ndyns = nbytes / dyn_size; 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * If this is an executable in PROGRAM view, then p_vaddr is an 4927c478bd9Sstevel@tonic-gate * absolute address; we need to subtract the virtual base address of 4937c478bd9Sstevel@tonic-gate * the mapping. In FILE view, dyn_addr is just the file offset. 4947c478bd9Sstevel@tonic-gate */ 4957c478bd9Sstevel@tonic-gate if (gf->gf_mode == GF_PROGRAM) { 4967c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0) 4977c478bd9Sstevel@tonic-gate dyn_addr = gf->gf_dynp->p_vaddr - gf->gf_phdrs->p_vaddr; 4987c478bd9Sstevel@tonic-gate else 4997c478bd9Sstevel@tonic-gate dyn_addr = gf->gf_dynp->p_vaddr; 5007c478bd9Sstevel@tonic-gate } else { 5017c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp = gf->gf_sects; 5027c478bd9Sstevel@tonic-gate 50330da1432Sahl for (i = 0; i < gf->gf_shnum; i++, gsp++) { 5047c478bd9Sstevel@tonic-gate if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) { 5057c478bd9Sstevel@tonic-gate dyn_addr = gsp->gs_shdr.sh_offset; 5067c478bd9Sstevel@tonic-gate break; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 51030da1432Sahl if (i == gf->gf_shnum) 5117c478bd9Sstevel@tonic-gate return (NULL); /* No SHT_DYNAMIC entry was found */ 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "loading _DYNAMIC[] (%lu entries) " 5157c478bd9Sstevel@tonic-gate "from offset %llx\n", (ulong_t)ndyns, (longlong_t)dyn_addr); 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, dyn_addr, SEEK_SET) == -1) { 5187c478bd9Sstevel@tonic-gate warn("failed to seek %s to _DYNAMIC", IOP_NAME(gf->gf_io)); 5197c478bd9Sstevel@tonic-gate return (NULL); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate dyns = mdb_alloc(nbytes, UM_SLEEP); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if (IOP_READ(gf->gf_io, dyns, nbytes) != nbytes) { 5257c478bd9Sstevel@tonic-gate warn("failed to read %s:_DYNAMIC", IOP_NAME(gf->gf_io)); 5267c478bd9Sstevel@tonic-gate mdb_free(dyns, nbytes); 5277c478bd9Sstevel@tonic-gate return (NULL); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP); 5317c478bd9Sstevel@tonic-gate gf->gf_ndyns = ndyns; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate dp = dyns; 5347c478bd9Sstevel@tonic-gate gdp = gf->gf_dyns; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) 5377c478bd9Sstevel@tonic-gate (void) elf2gelf(dp, gdp); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate mdb_free(dyns, nbytes); 5407c478bd9Sstevel@tonic-gate return (gf->gf_dyns); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 54430da1432Sahl gelf32_init(mdb_gelf_file_t *gf, mdb_io_t *io, const Elf32_Ehdr *ehdr) 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate * Convert the Elf32_Ehdr to a GElf_Ehdr 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate bcopy(ehdr->e_ident, gf->gf_ehdr.e_ident, EI_NIDENT); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_type = ehdr->e_type; 5527c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_machine = ehdr->e_machine; 5537c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_version = ehdr->e_version; 5547c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_entry = ehdr->e_entry; 5557c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_phoff = ehdr->e_phoff; 5567c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_shoff = ehdr->e_shoff; 5577c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_flags = ehdr->e_flags; 5587c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_ehsize = ehdr->e_ehsize; 5597c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_phentsize = ehdr->e_phentsize; 5607c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_phnum = ehdr->e_phnum; 5617c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_shentsize = ehdr->e_shentsize; 5627c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_shnum = ehdr->e_shnum; 5637c478bd9Sstevel@tonic-gate gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx; 5647c478bd9Sstevel@tonic-gate 56530da1432Sahl gf->gf_shnum = gf->gf_ehdr.e_shnum; 56630da1432Sahl gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx; 56730da1432Sahl gf->gf_phnum = gf->gf_ehdr.e_phnum; 56830da1432Sahl 56930da1432Sahl if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) || 57030da1432Sahl gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) { 57130da1432Sahl Elf32_Shdr shdr0; 57230da1432Sahl 57330da1432Sahl if (ehdr->e_shoff == 0) 57430da1432Sahl return (NULL); 57530da1432Sahl 57630da1432Sahl if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) { 57730da1432Sahl warn("failed to seek %s", IOP_NAME(io)); 57830da1432Sahl return (NULL); 57930da1432Sahl } 58030da1432Sahl 58130da1432Sahl if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) { 58230da1432Sahl warn("failed to read extended ELF header from %s", 58330da1432Sahl IOP_NAME(io)); 58430da1432Sahl return (NULL); 58530da1432Sahl } 58630da1432Sahl 58730da1432Sahl if (gf->gf_shnum == 0) 58830da1432Sahl gf->gf_shnum = shdr0.sh_size; 58930da1432Sahl 59030da1432Sahl if (gf->gf_shstrndx == SHN_XINDEX) 59130da1432Sahl gf->gf_shstrndx = shdr0.sh_link; 59230da1432Sahl 59330da1432Sahl if (gf->gf_phnum == PN_XNUM) 59430da1432Sahl gf->gf_phnum = shdr0.sh_info; 59530da1432Sahl } 59630da1432Sahl 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Initialize the section and program headers. We skip initializing 5997c478bd9Sstevel@tonic-gate * the section headers if this is a program image because they are 6007c478bd9Sstevel@tonic-gate * not loadable and thus we can't get at them. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf32_Shdr), 6037c478bd9Sstevel@tonic-gate (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf32_to_shdr) == NULL) 6047c478bd9Sstevel@tonic-gate return (NULL); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate if (gelf_phdrs_init(gf, sizeof (Elf32_Phdr), 6077c478bd9Sstevel@tonic-gate (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf32_to_phdr) == NULL) 6087c478bd9Sstevel@tonic-gate return (NULL); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn), 6117c478bd9Sstevel@tonic-gate (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate return (gf); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 61730da1432Sahl gelf64_init(mdb_gelf_file_t *gf, mdb_io_t *io, Elf64_Ehdr *ehdr) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate * Save a copy of the ELF file header 6217c478bd9Sstevel@tonic-gate */ 6227c478bd9Sstevel@tonic-gate bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr)); 6237c478bd9Sstevel@tonic-gate 62430da1432Sahl gf->gf_shnum = gf->gf_ehdr.e_shnum; 62530da1432Sahl gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx; 62630da1432Sahl gf->gf_phnum = gf->gf_ehdr.e_phnum; 62730da1432Sahl 62830da1432Sahl if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) || 62930da1432Sahl gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) { 63030da1432Sahl Elf64_Shdr shdr0; 63130da1432Sahl 63230da1432Sahl if (ehdr->e_shoff == 0) 63330da1432Sahl return (NULL); 63430da1432Sahl 63530da1432Sahl if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) { 63630da1432Sahl warn("failed to seek %s", IOP_NAME(io)); 63730da1432Sahl return (NULL); 63830da1432Sahl } 63930da1432Sahl 64030da1432Sahl if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) { 64130da1432Sahl warn("failed to read extended ELF header from %s", 64230da1432Sahl IOP_NAME(io)); 64330da1432Sahl return (NULL); 64430da1432Sahl } 64530da1432Sahl 64630da1432Sahl if (gf->gf_shnum == 0) 64730da1432Sahl gf->gf_shnum = shdr0.sh_size; 64830da1432Sahl 64930da1432Sahl if (gf->gf_shstrndx == SHN_XINDEX) 65030da1432Sahl gf->gf_shstrndx = shdr0.sh_link; 65130da1432Sahl 65230da1432Sahl if (gf->gf_phnum == PN_XNUM) 65330da1432Sahl gf->gf_phnum = shdr0.sh_info; 65430da1432Sahl } 65530da1432Sahl 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * Initialize the section and program headers. We skip initializing 6587c478bd9Sstevel@tonic-gate * the section headers if this is a program image because they are 6597c478bd9Sstevel@tonic-gate * not loadable and thus we can't get at them. 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf64_Shdr), 6627c478bd9Sstevel@tonic-gate (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf64_to_shdr) == NULL) 6637c478bd9Sstevel@tonic-gate return (NULL); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate if (gelf_phdrs_init(gf, sizeof (Elf64_Phdr), 6667c478bd9Sstevel@tonic-gate (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf64_to_phdr) == NULL) 6677c478bd9Sstevel@tonic-gate return (NULL); 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn), 6707c478bd9Sstevel@tonic-gate (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate return (gf); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate int 6767c478bd9Sstevel@tonic-gate mdb_gelf_check(mdb_io_t *io, Elf32_Ehdr *ehp, GElf_Half etype) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 6797c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2MSB; 6807c478bd9Sstevel@tonic-gate #else 6817c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2LSB; 6827c478bd9Sstevel@tonic-gate #endif 6837c478bd9Sstevel@tonic-gate ssize_t nbytes; 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); 6867c478bd9Sstevel@tonic-gate nbytes = IOP_READ(io, ehp, sizeof (Elf32_Ehdr)); 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate if (nbytes == -1) { 6897c478bd9Sstevel@tonic-gate if (etype != ET_NONE) 6907c478bd9Sstevel@tonic-gate warn("failed to read ELF header from %s", IOP_NAME(io)); 6917c478bd9Sstevel@tonic-gate return (-1); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate if (nbytes != sizeof (Elf32_Ehdr) || 6957c478bd9Sstevel@tonic-gate bcmp(&ehp->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) { 6967c478bd9Sstevel@tonic-gate if (etype != ET_NONE) 6977c478bd9Sstevel@tonic-gate warn("%s is not an ELF file\n", IOP_NAME(io)); 6987c478bd9Sstevel@tonic-gate return (-1); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (ehp->e_ident[EI_DATA] != order) { 7027c478bd9Sstevel@tonic-gate warn("ELF file %s has different endianness from debugger\n", 7037c478bd9Sstevel@tonic-gate IOP_NAME(io)); 7047c478bd9Sstevel@tonic-gate return (-1); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate if (ehp->e_version != EV_CURRENT) { 7087c478bd9Sstevel@tonic-gate warn("ELF file %s uses different ELF version (%lu) than " 7097c478bd9Sstevel@tonic-gate "debugger (%u)\n", IOP_NAME(io), 7107c478bd9Sstevel@tonic-gate (ulong_t)ehp->e_version, EV_CURRENT); 7117c478bd9Sstevel@tonic-gate return (-1); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate if (etype != ET_NONE && ehp->e_type != etype) { 7157c478bd9Sstevel@tonic-gate warn("ELF file %s is not of the expected type\n", IOP_NAME(io)); 7167c478bd9Sstevel@tonic-gate return (-1); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate return (0); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate mdb_gelf_file_t * 7237c478bd9Sstevel@tonic-gate mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate union { 7267c478bd9Sstevel@tonic-gate Elf32_Ehdr h32; 7277c478bd9Sstevel@tonic-gate Elf64_Ehdr h64; 7287c478bd9Sstevel@tonic-gate } ehdr; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate mdb_gelf_file_t *gf = mdb_zalloc(sizeof (mdb_gelf_file_t), UM_SLEEP); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate ASSERT(mode == GF_FILE || mode == GF_PROGRAM); 7337c478bd9Sstevel@tonic-gate gf->gf_mode = mode; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * Assign the i/o backend now, but don't hold it until we're sure 7377c478bd9Sstevel@tonic-gate * we're going to succeed; otherwise the caller will be responsible 7387c478bd9Sstevel@tonic-gate * for mdb_io_destroy()ing it. 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate gf->gf_io = io; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if (mdb_gelf_check(io, &ehdr.h32, etype) == -1) 7437c478bd9Sstevel@tonic-gate goto err; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate switch (ehdr.h32.e_ident[EI_CLASS]) { 7467c478bd9Sstevel@tonic-gate case ELFCLASS32: 74730da1432Sahl gf = gelf32_init(gf, io, &ehdr.h32); 7487c478bd9Sstevel@tonic-gate break; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate case ELFCLASS64: 7517c478bd9Sstevel@tonic-gate if (IOP_SEEK(io, (off64_t)0L, SEEK_SET) == -1) { 7527c478bd9Sstevel@tonic-gate warn("failed to seek %s", IOP_NAME(io)); 7537c478bd9Sstevel@tonic-gate goto err; 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate if (IOP_READ(io, &ehdr.h64, sizeof (ehdr.h64)) != 7577c478bd9Sstevel@tonic-gate sizeof (ehdr.h64)) { 7587c478bd9Sstevel@tonic-gate warn("failed to read ELF header from %s", IOP_NAME(io)); 7597c478bd9Sstevel@tonic-gate goto err; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 76230da1432Sahl gf = gelf64_init(gf, io, &ehdr.h64); 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate default: 7667c478bd9Sstevel@tonic-gate warn("%s is an unsupported ELF class: %u\n", 7677c478bd9Sstevel@tonic-gate IOP_NAME(io), ehdr.h32.e_ident[EI_CLASS]); 7687c478bd9Sstevel@tonic-gate goto err; 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate if (gf != NULL && gelf_sect_init(gf) != NULL) { 7727c478bd9Sstevel@tonic-gate gf->gf_io = mdb_io_hold(io); 7737c478bd9Sstevel@tonic-gate return (gf); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate err: 7777c478bd9Sstevel@tonic-gate if (gf != NULL) { 7787c478bd9Sstevel@tonic-gate if (gf->gf_sects != NULL) { 77930da1432Sahl mdb_free(gf->gf_sects, gf->gf_shnum * 7807c478bd9Sstevel@tonic-gate sizeof (mdb_gelf_sect_t)); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate mdb_free(gf, sizeof (mdb_gelf_file_t)); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate return (NULL); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate void 7887c478bd9Sstevel@tonic-gate mdb_gelf_destroy(mdb_gelf_file_t *gf) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 7917c478bd9Sstevel@tonic-gate GElf_Half i; 7927c478bd9Sstevel@tonic-gate 79330da1432Sahl for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 7947c478bd9Sstevel@tonic-gate if (gsp->gs_data != NULL) 7957c478bd9Sstevel@tonic-gate mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate mdb_free(gf->gf_sects, 79930da1432Sahl gf->gf_shnum * sizeof (mdb_gelf_sect_t)); 8007c478bd9Sstevel@tonic-gate 80130da1432Sahl mdb_free(gf->gf_phdrs, gf->gf_phnum * sizeof (GElf_Phdr)); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate mdb_io_rele(gf->gf_io); 8047c478bd9Sstevel@tonic-gate mdb_free(gf, sizeof (mdb_gelf_file_t)); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate /* 8087c478bd9Sstevel@tonic-gate * Sort comparison function for 32-bit symbol address-to-name lookups. We sort 8097c478bd9Sstevel@tonic-gate * symbols by value. If values are equal, we prefer the symbol that is 8107c478bd9Sstevel@tonic-gate * non-zero sized, typed, not weak, or lexically first, in that order. 8117c478bd9Sstevel@tonic-gate */ 8127c478bd9Sstevel@tonic-gate static int 8137c478bd9Sstevel@tonic-gate gelf32_sym_compare(const void *lp, const void *rp) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate Elf32_Sym *lhs = *((Elf32_Sym **)lp); 8167c478bd9Sstevel@tonic-gate Elf32_Sym *rhs = *((Elf32_Sym **)rp); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate if (lhs->st_value != rhs->st_value) 8197c478bd9Sstevel@tonic-gate return (lhs->st_value > rhs->st_value ? 1 : -1); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate if ((lhs->st_size == 0) != (rhs->st_size == 0)) 8227c478bd9Sstevel@tonic-gate return (lhs->st_size == 0 ? 1 : -1); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 8257c478bd9Sstevel@tonic-gate (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 8267c478bd9Sstevel@tonic-gate return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != 8297c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) 8307c478bd9Sstevel@tonic-gate return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name)); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * Sort comparison function for 64-bit symbol address-to-name lookups. We sort 8377c478bd9Sstevel@tonic-gate * symbols by value. If values are equal, we prefer the symbol that is 8387c478bd9Sstevel@tonic-gate * non-zero sized, typed, not weak, or lexically first, in that order. 8397c478bd9Sstevel@tonic-gate */ 8407c478bd9Sstevel@tonic-gate static int 8417c478bd9Sstevel@tonic-gate gelf64_sym_compare(const void *lp, const void *rp) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate Elf64_Sym *lhs = *((Elf64_Sym **)lp); 8447c478bd9Sstevel@tonic-gate Elf64_Sym *rhs = *((Elf64_Sym **)rp); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (lhs->st_value != rhs->st_value) 8477c478bd9Sstevel@tonic-gate return (lhs->st_value > rhs->st_value ? 1 : -1); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if ((lhs->st_size == 0) != (rhs->st_size == 0)) 8507c478bd9Sstevel@tonic-gate return (lhs->st_size == 0 ? 1 : -1); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 8537c478bd9Sstevel@tonic-gate (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 8547c478bd9Sstevel@tonic-gate return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != 8577c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) 8587c478bd9Sstevel@tonic-gate return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name)); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate static void 8647c478bd9Sstevel@tonic-gate gelf32_symtab_sort(mdb_gelf_symtab_t *gst) 8657c478bd9Sstevel@tonic-gate { 8667c478bd9Sstevel@tonic-gate Elf32_Sym **sympp = (Elf32_Sym **)gst->gst_asmap; 8677c478bd9Sstevel@tonic-gate mdb_var_t *v; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate mdb_nv_rewind(&gst->gst_nv); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 8727c478bd9Sstevel@tonic-gate Elf32_Sym *sym = MDB_NV_COOKIE(v); 8737c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 8747c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 8757c478bd9Sstevel@tonic-gate *sympp++ = sym; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate gst->gst_aslen = (size_t)(sympp - (Elf32_Sym **)gst->gst_asmap); 8797c478bd9Sstevel@tonic-gate ASSERT(gst->gst_aslen <= gst->gst_asrsv); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate qsort(gst->gst_asmap, gst->gst_aslen, 8847c478bd9Sstevel@tonic-gate sizeof (Elf32_Sym *), gelf32_sym_compare); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate gelf_strtab = NULL; 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate static void 8907c478bd9Sstevel@tonic-gate gelf32_symtab_init(mdb_gelf_symtab_t *gst) 8917c478bd9Sstevel@tonic-gate { 8927c478bd9Sstevel@tonic-gate const char *base = (const char *)gst->gst_ssect->gs_data; 8937c478bd9Sstevel@tonic-gate Elf32_Sym *sym = gst->gst_dsect->gs_data; 8947c478bd9Sstevel@tonic-gate mdb_nv_t *nv = &gst->gst_nv; 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate Elf32_Word ss_size = gst->gst_ssect->gs_shdr.sh_size; 8977c478bd9Sstevel@tonic-gate size_t asrsv = 0; 8987c478bd9Sstevel@tonic-gate GElf_Word i, n; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf32_Sym)) { 9017c478bd9Sstevel@tonic-gate warn("%s sh_entsize %llu != sizeof (Elf32_Sym); " 9027c478bd9Sstevel@tonic-gate "using %u instead\n", gst->gst_dsect->gs_name, 9037c478bd9Sstevel@tonic-gate (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 9047c478bd9Sstevel@tonic-gate (uint_t)sizeof (Elf32_Sym)); 9057c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf32_Sym); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate n = gst->gst_dsect->gs_shdr.sh_size / 9097c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++, sym++) { 9127c478bd9Sstevel@tonic-gate const char *name = base + sym->st_name; 9137c478bd9Sstevel@tonic-gate uchar_t type = ELF32_ST_TYPE(sym->st_info); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate if (type >= STT_NUM || type == STT_SECTION) 9167c478bd9Sstevel@tonic-gate continue; /* skip sections and unknown types */ 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 9197c478bd9Sstevel@tonic-gate if (sym->st_name >= ss_size || name[0] != '\0') { 9207c478bd9Sstevel@tonic-gate warn("ignoring %s symbol [%u]: invalid name\n", 9217c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_name, i); 9227c478bd9Sstevel@tonic-gate sym->st_name = 0; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate continue; /* skip corrupt or empty names */ 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 9307c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 9317c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in the address map */ 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 93530da1432Sahl GElf_Word smax = gst->gst_file->gf_shnum; 9367c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 9397c478bd9Sstevel@tonic-gate if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 9407c478bd9Sstevel@tonic-gate gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 9417c478bd9Sstevel@tonic-gate sym->st_value += gsp->gs_shdr.sh_offset; 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || 9447c478bd9Sstevel@tonic-gate sym->st_size != 0) 9457c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in asmap */ 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate gst->gst_asmap = mdb_alloc(sizeof (Elf32_Sym *) * asrsv, UM_SLEEP); 9517c478bd9Sstevel@tonic-gate gst->gst_asrsv = asrsv; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate gelf32_symtab_sort(gst); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate static void 9577c478bd9Sstevel@tonic-gate gelf64_symtab_sort(mdb_gelf_symtab_t *gst) 9587c478bd9Sstevel@tonic-gate { 9597c478bd9Sstevel@tonic-gate Elf64_Sym **sympp = (Elf64_Sym **)gst->gst_asmap; 9607c478bd9Sstevel@tonic-gate mdb_var_t *v; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate mdb_nv_rewind(&gst->gst_nv); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 9657c478bd9Sstevel@tonic-gate Elf64_Sym *sym = MDB_NV_COOKIE(v); 9667c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 9677c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 9687c478bd9Sstevel@tonic-gate *sympp++ = sym; 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate gst->gst_aslen = (size_t)(sympp - (Elf64_Sym **)gst->gst_asmap); 9727c478bd9Sstevel@tonic-gate ASSERT(gst->gst_aslen <= gst->gst_asrsv); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate qsort(gst->gst_asmap, gst->gst_aslen, 9777c478bd9Sstevel@tonic-gate sizeof (Elf64_Sym *), gelf64_sym_compare); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate gelf_strtab = NULL; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate static void 9837c478bd9Sstevel@tonic-gate gelf64_symtab_init(mdb_gelf_symtab_t *gst) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate const char *base = (const char *)gst->gst_ssect->gs_data; 9867c478bd9Sstevel@tonic-gate Elf64_Sym *sym = gst->gst_dsect->gs_data; 9877c478bd9Sstevel@tonic-gate mdb_nv_t *nv = &gst->gst_nv; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate Elf64_Xword ss_size = gst->gst_ssect->gs_shdr.sh_size; 9907c478bd9Sstevel@tonic-gate size_t asrsv = 0; 9917c478bd9Sstevel@tonic-gate GElf_Word i, n; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf64_Sym)) { 9947c478bd9Sstevel@tonic-gate warn("%s sh_entsize %llu != sizeof (Elf64_Sym); " 9957c478bd9Sstevel@tonic-gate "using %u instead\n", gst->gst_dsect->gs_name, 9967c478bd9Sstevel@tonic-gate (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 9977c478bd9Sstevel@tonic-gate (uint_t)sizeof (Elf64_Sym)); 9987c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf64_Sym); 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate n = gst->gst_dsect->gs_shdr.sh_size / 10027c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++, sym++) { 10057c478bd9Sstevel@tonic-gate const char *name = base + sym->st_name; 10067c478bd9Sstevel@tonic-gate uchar_t type = ELF64_ST_TYPE(sym->st_info); 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate if (type >= STT_NUM || type == STT_SECTION) 10097c478bd9Sstevel@tonic-gate continue; /* skip sections and unknown types */ 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 10127c478bd9Sstevel@tonic-gate if (sym->st_name >= ss_size || name[0] != '\0') { 10137c478bd9Sstevel@tonic-gate warn("ignoring %s symbol [%u]: invalid name\n", 10147c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_name, i); 10157c478bd9Sstevel@tonic-gate sym->st_name = 0; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate continue; /* skip corrupt or empty names */ 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 10237c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 10247c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in the address map */ 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 102830da1432Sahl GElf_Word smax = gst->gst_file->gf_shnum; 10297c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 10327c478bd9Sstevel@tonic-gate if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 10337c478bd9Sstevel@tonic-gate gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 10347c478bd9Sstevel@tonic-gate sym->st_value += gsp->gs_shdr.sh_offset; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || 10377c478bd9Sstevel@tonic-gate sym->st_size != 0) 10387c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in asmap */ 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate gst->gst_asmap = mdb_alloc(sizeof (Elf64_Sym *) * asrsv, UM_SLEEP); 10447c478bd9Sstevel@tonic-gate gst->gst_asrsv = asrsv; 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate gelf64_symtab_sort(gst); 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t * 10507c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype, 10517c478bd9Sstevel@tonic-gate uint_t tabid) 10527c478bd9Sstevel@tonic-gate { 10537c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 10547c478bd9Sstevel@tonic-gate const char *dsname = NULL; 10557c478bd9Sstevel@tonic-gate const char *ssname; 10567c478bd9Sstevel@tonic-gate GElf_Half i; 10577c478bd9Sstevel@tonic-gate GElf_Word link; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Examine the sh_link field in the the Elf header to get the name 10617c478bd9Sstevel@tonic-gate * of the corresponding strings section 10627c478bd9Sstevel@tonic-gate */ 106330da1432Sahl for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 10647c478bd9Sstevel@tonic-gate if (gsp->gs_shdr.sh_type == elftype) { 10657c478bd9Sstevel@tonic-gate dsname = gsp->gs_name; 10667c478bd9Sstevel@tonic-gate link = gsp->gs_shdr.sh_link; 10677c478bd9Sstevel@tonic-gate break; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (dsname == NULL) 10727c478bd9Sstevel@tonic-gate return (NULL); 10737c478bd9Sstevel@tonic-gate 107430da1432Sahl if (link > gf->gf_shnum) { 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * Invalid link number due to corrupt elf file. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate warn("link number %ud larger than number of sections %d\n", 107930da1432Sahl link, gf->gf_shnum); 10807c478bd9Sstevel@tonic-gate return (NULL); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate ssname = (gf->gf_sects + link)->gs_name; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate return (mdb_gelf_symtab_create_file_by_name(gf, dsname, ssname, tabid)); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t * 10897c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf, 10907c478bd9Sstevel@tonic-gate const char *dsname, const char *ssname, uint_t tabid) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 10937c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp; 10947c478bd9Sstevel@tonic-gate GElf_Half i; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 10977c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate gst->gst_asmap = NULL; 11007c478bd9Sstevel@tonic-gate gst->gst_aslen = 0; 11017c478bd9Sstevel@tonic-gate gst->gst_asrsv = 0; 11027c478bd9Sstevel@tonic-gate gst->gst_ehdr = &gf->gf_ehdr; 11037c478bd9Sstevel@tonic-gate gst->gst_file = gf; 11047c478bd9Sstevel@tonic-gate gst->gst_dsect = NULL; 11057c478bd9Sstevel@tonic-gate gst->gst_ssect = NULL; 11067c478bd9Sstevel@tonic-gate gst->gst_id = 0; 11077c478bd9Sstevel@tonic-gate gst->gst_tabid = tabid; 11087c478bd9Sstevel@tonic-gate 110930da1432Sahl for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 11107c478bd9Sstevel@tonic-gate if (strcmp(gsp->gs_name, dsname) == 0) { 11117c478bd9Sstevel@tonic-gate gst->gst_dsect = gsp; 11127c478bd9Sstevel@tonic-gate break; 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 111630da1432Sahl for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 11177c478bd9Sstevel@tonic-gate if (strcmp(gsp->gs_name, ssname) == 0) { 11187c478bd9Sstevel@tonic-gate gst->gst_ssect = gsp; 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (gst->gst_dsect == NULL || gst->gst_ssect == NULL) 11247c478bd9Sstevel@tonic-gate goto err; /* Failed to locate data or string section */ 11257c478bd9Sstevel@tonic-gate 1126*a576ab5bSrab if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL) 11277c478bd9Sstevel@tonic-gate goto err; /* Failed to load data section */ 11287c478bd9Sstevel@tonic-gate 1129*a576ab5bSrab if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL) 11307c478bd9Sstevel@tonic-gate goto err; /* Failed to load string section */ 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 11337c478bd9Sstevel@tonic-gate gelf32_symtab_init(gst); 11347c478bd9Sstevel@tonic-gate else 11357c478bd9Sstevel@tonic-gate gelf64_symtab_init(gst); 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate return (gst); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate err: 11407c478bd9Sstevel@tonic-gate mdb_nv_destroy(&gst->gst_nv); 11417c478bd9Sstevel@tonic-gate mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 11427c478bd9Sstevel@tonic-gate return (NULL); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t * 11467c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_raw(const GElf_Ehdr *ehdr, const void *dshdr, 11477c478bd9Sstevel@tonic-gate void *ddata, const void *sshdr, void *sdata, uint_t tabid) 11487c478bd9Sstevel@tonic-gate { 11497c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 11527c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate gst->gst_asmap = NULL; 11557c478bd9Sstevel@tonic-gate gst->gst_aslen = 0; 11567c478bd9Sstevel@tonic-gate gst->gst_asrsv = 0; 11577c478bd9Sstevel@tonic-gate gst->gst_ehdr = ehdr; 11587c478bd9Sstevel@tonic-gate gst->gst_file = NULL; /* Flag for raw symtab */ 11597c478bd9Sstevel@tonic-gate gst->gst_id = 0; 11607c478bd9Sstevel@tonic-gate gst->gst_tabid = tabid; 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 11637c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_name = ".symtab"; 11647c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_data = ddata; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 11677c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_name = ".strtab"; 11687c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_data = sdata; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 11717c478bd9Sstevel@tonic-gate (void) gelf32_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 11727c478bd9Sstevel@tonic-gate (void) gelf32_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 11737c478bd9Sstevel@tonic-gate gelf32_symtab_init(gst); 11747c478bd9Sstevel@tonic-gate } else { 11757c478bd9Sstevel@tonic-gate (void) gelf64_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 11767c478bd9Sstevel@tonic-gate (void) gelf64_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 11777c478bd9Sstevel@tonic-gate gelf64_symtab_init(gst); 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate return (gst); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t * 11847c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t *gf, uint_t tabid) 11857c478bd9Sstevel@tonic-gate { 11867c478bd9Sstevel@tonic-gate GElf_Addr dt_symtab, dt_strtab, dt_hash; 11877c478bd9Sstevel@tonic-gate GElf_Xword dt_syment, dt_strsz; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 11907c478bd9Sstevel@tonic-gate uint_t hash_h[2]; 11917c478bd9Sstevel@tonic-gate off64_t base = 0; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate ASSERT(gf->gf_mode == GF_PROGRAM); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* 11967c478bd9Sstevel@tonic-gate * Read in and cache the array of GElf_Dyn structures from the 11977c478bd9Sstevel@tonic-gate * PT_DYNAMIC phdr. Abort if this is not possible. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 12007c478bd9Sstevel@tonic-gate (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn), 12017c478bd9Sstevel@tonic-gate (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn); 12027c478bd9Sstevel@tonic-gate } else { 12037c478bd9Sstevel@tonic-gate (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn), 12047c478bd9Sstevel@tonic-gate (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * Pre-fetch all the DT_* entries we will need for creating the 12097c478bd9Sstevel@tonic-gate * dynamic symbol table; abort if any are missing. 12107c478bd9Sstevel@tonic-gate */ 12117c478bd9Sstevel@tonic-gate if ((dt_hash = gelf_dyn_lookup(gf, DT_HASH)) == -1L) { 12127c478bd9Sstevel@tonic-gate warn("failed to get DT_HASH for %s\n", IOP_NAME(gf->gf_io)); 12137c478bd9Sstevel@tonic-gate return (NULL); 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate if ((dt_symtab = gelf_dyn_lookup(gf, DT_SYMTAB)) == -1L) { 12177c478bd9Sstevel@tonic-gate warn("failed to get DT_SYMTAB for %s\n", IOP_NAME(gf->gf_io)); 12187c478bd9Sstevel@tonic-gate return (NULL); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if ((dt_syment = gelf_dyn_lookup(gf, DT_SYMENT)) == -1L) { 12227c478bd9Sstevel@tonic-gate warn("failed to get DT_SYMENT for %s\n", IOP_NAME(gf->gf_io)); 12237c478bd9Sstevel@tonic-gate return (NULL); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if ((dt_strtab = gelf_dyn_lookup(gf, DT_STRTAB)) == -1L) { 12277c478bd9Sstevel@tonic-gate warn("failed to get DT_STRTAB for %s\n", IOP_NAME(gf->gf_io)); 12287c478bd9Sstevel@tonic-gate return (NULL); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate if ((dt_strsz = gelf_dyn_lookup(gf, DT_STRSZ)) == -1L) { 12327c478bd9Sstevel@tonic-gate warn("failed to get DT_STRSZ for %s\n", IOP_NAME(gf->gf_io)); 12337c478bd9Sstevel@tonic-gate return (NULL); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * If this is an executable, then DT_HASH is an absolute address; 12387c478bd9Sstevel@tonic-gate * we need to subtract the virtual base address of the mapping. 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0) 12417c478bd9Sstevel@tonic-gate base = (off64_t)gf->gf_phdrs->p_vaddr; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * Read in the header for the DT_HASH: this consists of nbucket 12457c478bd9Sstevel@tonic-gate * and nchain values (nchain is the number of hashed symbols). 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate if (IOP_SEEK(gf->gf_io, (off64_t)dt_hash - base, SEEK_SET) == -1) { 12487c478bd9Sstevel@tonic-gate warn("failed to seek ELF file to start of DT_HASH"); 12497c478bd9Sstevel@tonic-gate return (NULL); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate if (IOP_READ(gf->gf_io, hash_h, sizeof (hash_h)) != sizeof (hash_h)) { 12537c478bd9Sstevel@tonic-gate warn("failed to read DT_HASH header"); 12547c478bd9Sstevel@tonic-gate return (NULL); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 12587c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate gst->gst_asmap = NULL; 12617c478bd9Sstevel@tonic-gate gst->gst_aslen = 0; 12627c478bd9Sstevel@tonic-gate gst->gst_asrsv = 0; 12637c478bd9Sstevel@tonic-gate gst->gst_ehdr = &gf->gf_ehdr; 12647c478bd9Sstevel@tonic-gate gst->gst_file = gf; 12657c478bd9Sstevel@tonic-gate gst->gst_id = 0; 12667c478bd9Sstevel@tonic-gate gst->gst_tabid = tabid; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 12697c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_name = ".dynsym"; 12707c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_offset = dt_symtab - (GElf_Addr)base; 12717c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_size = hash_h[1] * dt_syment; 12727c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize = dt_syment; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 12757c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_name = ".dynstr"; 12767c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_shdr.sh_offset = dt_strtab - (GElf_Addr)base; 12777c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_shdr.sh_size = dt_strsz; 12787c478bd9Sstevel@tonic-gate gst->gst_ssect->gs_shdr.sh_entsize = 0; 12797c478bd9Sstevel@tonic-gate 1280*a576ab5bSrab if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL) 12817c478bd9Sstevel@tonic-gate goto err; 12827c478bd9Sstevel@tonic-gate 1283*a576ab5bSrab if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL) 12847c478bd9Sstevel@tonic-gate goto err; 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 12877c478bd9Sstevel@tonic-gate gelf32_symtab_init(gst); 12887c478bd9Sstevel@tonic-gate else 12897c478bd9Sstevel@tonic-gate gelf64_symtab_init(gst); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate return (gst); 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate err: 12947c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(gst); 12957c478bd9Sstevel@tonic-gate return (NULL); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t * 12997c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_mutable(void) 13007c478bd9Sstevel@tonic-gate { 13017c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 13027c478bd9Sstevel@tonic-gate static GElf_Ehdr ehdr; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 13057c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 13067c478bd9Sstevel@tonic-gate gst->gst_ehdr = &ehdr; 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate if (ehdr.e_version == 0) { 13097c478bd9Sstevel@tonic-gate #ifdef _LP64 13107c478bd9Sstevel@tonic-gate uchar_t class = ELFCLASS64; 13117c478bd9Sstevel@tonic-gate #else 13127c478bd9Sstevel@tonic-gate uchar_t class = ELFCLASS32; 13137c478bd9Sstevel@tonic-gate #endif 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 13167c478bd9Sstevel@tonic-gate uchar_t data = ELFDATA2MSB; 13177c478bd9Sstevel@tonic-gate #else 13187c478bd9Sstevel@tonic-gate uchar_t data = ELFDATA2LSB; 13197c478bd9Sstevel@tonic-gate #endif 13207c478bd9Sstevel@tonic-gate /* 13217c478bd9Sstevel@tonic-gate * Since all mutable symbol tables will use a native Ehdr, 13227c478bd9Sstevel@tonic-gate * we can just have a single static copy which they all 13237c478bd9Sstevel@tonic-gate * point to and we only need initialize once. 13247c478bd9Sstevel@tonic-gate */ 13257c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_MAG0] = ELFMAG0; 13267c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_MAG1] = ELFMAG1; 13277c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_MAG2] = ELFMAG2; 13287c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_MAG3] = ELFMAG3; 13297c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_CLASS] = class; 13307c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_DATA] = data; 13317c478bd9Sstevel@tonic-gate ehdr.e_ident[EI_VERSION] = EV_CURRENT; 13327c478bd9Sstevel@tonic-gate ehdr.e_type = ET_NONE; 13337c478bd9Sstevel@tonic-gate ehdr.e_version = EV_CURRENT; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate return (gst); 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate void 13407c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(mdb_gelf_symtab_t *gst) 13417c478bd9Sstevel@tonic-gate { 13427c478bd9Sstevel@tonic-gate if (gst->gst_file == NULL) { 13437c478bd9Sstevel@tonic-gate if (gst->gst_dsect == NULL && gst->gst_ssect == NULL) { 13447c478bd9Sstevel@tonic-gate mdb_var_t *v; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate mdb_nv_rewind(&gst->gst_nv); 13477c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 13487c478bd9Sstevel@tonic-gate char *name = (char *)mdb_nv_get_name(v); 13497c478bd9Sstevel@tonic-gate mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 13527c478bd9Sstevel@tonic-gate mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate } else { 13567c478bd9Sstevel@tonic-gate mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 13577c478bd9Sstevel@tonic-gate mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate } else if (gst->gst_file->gf_mode == GF_PROGRAM) { 13617c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *dsect = gst->gst_dsect; 13627c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *ssect = gst->gst_ssect; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate if (dsect->gs_data != NULL) 13657c478bd9Sstevel@tonic-gate mdb_free(dsect->gs_data, dsect->gs_shdr.sh_size); 13667c478bd9Sstevel@tonic-gate if (ssect->gs_data != NULL) 13677c478bd9Sstevel@tonic-gate mdb_free(ssect->gs_data, ssect->gs_shdr.sh_size); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 13707c478bd9Sstevel@tonic-gate mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate mdb_nv_destroy(&gst->gst_nv); 13747c478bd9Sstevel@tonic-gate mdb_free(gst->gst_asmap, gst->gst_asrsv * sizeof (void *)); 13757c478bd9Sstevel@tonic-gate mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate size_t 13797c478bd9Sstevel@tonic-gate mdb_gelf_symtab_size(mdb_gelf_symtab_t *gst) 13807c478bd9Sstevel@tonic-gate { 13817c478bd9Sstevel@tonic-gate return (mdb_nv_size(&gst->gst_nv)); 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate static GElf_Sym * 13857c478bd9Sstevel@tonic-gate gelf32_to_sym(const Elf32_Sym *src, GElf_Sym *dst) 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate if (src != NULL) { 13887c478bd9Sstevel@tonic-gate dst->st_name = src->st_name; 13897c478bd9Sstevel@tonic-gate dst->st_info = src->st_info; 13907c478bd9Sstevel@tonic-gate dst->st_other = src->st_other; 13917c478bd9Sstevel@tonic-gate dst->st_shndx = src->st_shndx; 13927c478bd9Sstevel@tonic-gate dst->st_value = src->st_value; 13937c478bd9Sstevel@tonic-gate dst->st_size = src->st_size; 13947c478bd9Sstevel@tonic-gate return (dst); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate return (NULL); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate static GElf_Sym * 14017c478bd9Sstevel@tonic-gate gelf64_to_sym(const Elf64_Sym *src, GElf_Sym *dst) 14027c478bd9Sstevel@tonic-gate { 14037c478bd9Sstevel@tonic-gate if (src != NULL) { 14047c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (GElf_Sym)); 14057c478bd9Sstevel@tonic-gate return (dst); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate return (NULL); 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14127c478bd9Sstevel@tonic-gate static GElf_Sym * 14137c478bd9Sstevel@tonic-gate gelf64_nocopy(const Elf64_Sym *src, GElf_Sym *dst) 14147c478bd9Sstevel@tonic-gate { 14157c478bd9Sstevel@tonic-gate return ((GElf_Sym *)src); 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate static const void * 14197c478bd9Sstevel@tonic-gate gelf32_sym_search(const Elf32_Sym **asmap, size_t aslen, uintptr_t addr) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate ulong_t i, mid, lo = 0, hi = aslen - 1; 14227c478bd9Sstevel@tonic-gate const Elf32_Sym *symp; 14237c478bd9Sstevel@tonic-gate Elf32_Addr v; 14247c478bd9Sstevel@tonic-gate size_t size; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate if (aslen == 0) 14277c478bd9Sstevel@tonic-gate return (NULL); 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate while (hi - lo > 1) { 14307c478bd9Sstevel@tonic-gate mid = (lo + hi) / 2; 14317c478bd9Sstevel@tonic-gate if (addr >= asmap[mid]->st_value) 14327c478bd9Sstevel@tonic-gate lo = mid; 14337c478bd9Sstevel@tonic-gate else 14347c478bd9Sstevel@tonic-gate hi = mid; 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate i = addr < asmap[hi]->st_value ? lo : hi; 14387c478bd9Sstevel@tonic-gate symp = asmap[i]; 14397c478bd9Sstevel@tonic-gate v = symp->st_value; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate /* 14427c478bd9Sstevel@tonic-gate * If the previous entry has the same value, improve our choice. The 14437c478bd9Sstevel@tonic-gate * order of equal-valued symbols is determined by gelf32_sym_compare(). 14447c478bd9Sstevel@tonic-gate */ 14457c478bd9Sstevel@tonic-gate while (i-- != 0 && asmap[i]->st_value == v) 14467c478bd9Sstevel@tonic-gate symp = asmap[i]; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * If an absolute symbol distance was specified, use that; otherwise 14507c478bd9Sstevel@tonic-gate * use the ELF symbol size, or 1 byte if the ELF size is zero. 14517c478bd9Sstevel@tonic-gate */ 14527c478bd9Sstevel@tonic-gate if (mdb.m_symdist == 0) 14537c478bd9Sstevel@tonic-gate size = MAX(symp->st_size, 1); 14547c478bd9Sstevel@tonic-gate else 14557c478bd9Sstevel@tonic-gate size = mdb.m_symdist; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate if (addr - symp->st_value < size) 14587c478bd9Sstevel@tonic-gate return (symp); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate return (NULL); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate static const void * 14647c478bd9Sstevel@tonic-gate gelf64_sym_search(const Elf64_Sym **asmap, size_t aslen, uintptr_t addr) 14657c478bd9Sstevel@tonic-gate { 14667c478bd9Sstevel@tonic-gate ulong_t i, mid, lo = 0, hi = aslen - 1; 14677c478bd9Sstevel@tonic-gate const Elf64_Sym *symp; 14687c478bd9Sstevel@tonic-gate Elf64_Addr v; 14697c478bd9Sstevel@tonic-gate size_t size; 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate if (aslen == 0) 14727c478bd9Sstevel@tonic-gate return (NULL); 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate while (hi - lo > 1) { 14757c478bd9Sstevel@tonic-gate mid = (lo + hi) / 2; 14767c478bd9Sstevel@tonic-gate if (addr >= asmap[mid]->st_value) 14777c478bd9Sstevel@tonic-gate lo = mid; 14787c478bd9Sstevel@tonic-gate else 14797c478bd9Sstevel@tonic-gate hi = mid; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate i = addr < asmap[hi]->st_value ? lo : hi; 14837c478bd9Sstevel@tonic-gate symp = asmap[i]; 14847c478bd9Sstevel@tonic-gate v = symp->st_value; 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* 14877c478bd9Sstevel@tonic-gate * If the previous entry has the same value, improve our choice. The 14887c478bd9Sstevel@tonic-gate * order of equal-valued symbols is determined by gelf64_sym_compare(). 14897c478bd9Sstevel@tonic-gate */ 14907c478bd9Sstevel@tonic-gate while (i-- != 0 && asmap[i]->st_value == v) 14917c478bd9Sstevel@tonic-gate symp = asmap[i]; 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * If an absolute symbol distance was specified, use that; otherwise 14957c478bd9Sstevel@tonic-gate * use the ELF symbol size, or 1 byte if the ELF size is zero. 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate if (mdb.m_symdist == 0) 14987c478bd9Sstevel@tonic-gate size = MAX(symp->st_size, 1); 14997c478bd9Sstevel@tonic-gate else 15007c478bd9Sstevel@tonic-gate size = mdb.m_symdist; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate if (addr - symp->st_value < size) 15037c478bd9Sstevel@tonic-gate return (symp); 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate return (NULL); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate const char * 15097c478bd9Sstevel@tonic-gate mdb_gelf_sym_name(mdb_gelf_symtab_t *gst, const GElf_Sym *sym) 15107c478bd9Sstevel@tonic-gate { 15117c478bd9Sstevel@tonic-gate const mdb_gelf_dsym_t *dsp; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate if (gst->gst_ssect != NULL) 15147c478bd9Sstevel@tonic-gate return ((const char *)gst->gst_ssect->gs_data + sym->st_name); 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 15177c478bd9Sstevel@tonic-gate dsp = gelf32_sym_search(gst->gst_asmap, 15187c478bd9Sstevel@tonic-gate gst->gst_aslen, sym->st_value); 15197c478bd9Sstevel@tonic-gate else 15207c478bd9Sstevel@tonic-gate dsp = gelf64_sym_search(gst->gst_asmap, 15217c478bd9Sstevel@tonic-gate gst->gst_aslen, sym->st_value); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate if (dsp != NULL) 15247c478bd9Sstevel@tonic-gate return (mdb_nv_get_name(dsp->ds_var)); 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate return (NULL); 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate int 15307c478bd9Sstevel@tonic-gate mdb_gelf_sym_closer(const GElf_Sym *s1, const GElf_Sym *s2, uintptr_t addr) 15317c478bd9Sstevel@tonic-gate { 15327c478bd9Sstevel@tonic-gate uintptr_t v1 = (uintptr_t)s1->st_value; 15337c478bd9Sstevel@tonic-gate uintptr_t v2 = (uintptr_t)s2->st_value; 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate uintptr_t d1 = v1 > addr ? v1 - addr : addr - v1; 15367c478bd9Sstevel@tonic-gate uintptr_t d2 = v2 > addr ? v2 - addr : addr - v2; 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate return (d1 < d2); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate int 15427c478bd9Sstevel@tonic-gate mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t *gst, uintptr_t addr, 15437c478bd9Sstevel@tonic-gate uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym, uint_t *idp) 15447c478bd9Sstevel@tonic-gate { 15457c478bd9Sstevel@tonic-gate union { 15467c478bd9Sstevel@tonic-gate const mdb_gelf_dsym_t *dsp; 15477c478bd9Sstevel@tonic-gate const Elf32_Sym *s32; 15487c478bd9Sstevel@tonic-gate const Elf64_Sym *s64; 15497c478bd9Sstevel@tonic-gate caddr_t sp; 15507c478bd9Sstevel@tonic-gate } u; 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate const char *name; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if (gst == NULL) 15557c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 15587c478bd9Sstevel@tonic-gate u.s32 = gelf32_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 15597c478bd9Sstevel@tonic-gate if (gelf32_to_sym(u.s32, sym) == NULL) 15607c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 15617c478bd9Sstevel@tonic-gate } else { 15627c478bd9Sstevel@tonic-gate u.s64 = gelf64_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 15637c478bd9Sstevel@tonic-gate if (gelf64_to_sym(u.s64, sym) == NULL) 15647c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate if ((flags & GST_EXACT) && (sym->st_value != addr)) 15687c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (gst->gst_ssect != NULL) { 15717c478bd9Sstevel@tonic-gate name = (const char *)gst->gst_ssect->gs_data + sym->st_name; 15727c478bd9Sstevel@tonic-gate if (idp != NULL) { 15737c478bd9Sstevel@tonic-gate *idp = (u.sp - (caddr_t)gst->gst_dsect->gs_data) / 15747c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate } else { 15777c478bd9Sstevel@tonic-gate name = mdb_nv_get_name(u.dsp->ds_var); 15787c478bd9Sstevel@tonic-gate if (idp != NULL) 15797c478bd9Sstevel@tonic-gate *idp = u.dsp->ds_id; 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate if (nbytes > 0) { 15837c478bd9Sstevel@tonic-gate (void) strncpy(buf, name, nbytes - 1); 15847c478bd9Sstevel@tonic-gate buf[nbytes - 1] = '\0'; 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate return (0); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate int 15907c478bd9Sstevel@tonic-gate mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t *gst, const char *name, 15917c478bd9Sstevel@tonic-gate GElf_Sym *sym, uint_t *idp) 15927c478bd9Sstevel@tonic-gate { 15937c478bd9Sstevel@tonic-gate mdb_var_t *v; 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate if (gst != NULL && (v = mdb_nv_lookup(&gst->gst_nv, name)) != NULL) { 15967c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 15977c478bd9Sstevel@tonic-gate (void) gelf32_to_sym(mdb_nv_get_cookie(v), sym); 15987c478bd9Sstevel@tonic-gate else 15997c478bd9Sstevel@tonic-gate (void) gelf64_to_sym(mdb_nv_get_cookie(v), sym); 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate if (idp != NULL) { 16027c478bd9Sstevel@tonic-gate if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 16037c478bd9Sstevel@tonic-gate mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 16047c478bd9Sstevel@tonic-gate *idp = dsp->ds_id; 16057c478bd9Sstevel@tonic-gate } else { 16067c478bd9Sstevel@tonic-gate *idp = ((uintptr_t)mdb_nv_get_cookie(v) - 16077c478bd9Sstevel@tonic-gate (uintptr_t)gst->gst_dsect->gs_data) / 16087c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_shdr.sh_entsize; 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate return (0); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate int 16197c478bd9Sstevel@tonic-gate mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t *gst, const char *file, 16207c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *sym, uint_t *idp) 16217c478bd9Sstevel@tonic-gate { 16227c478bd9Sstevel@tonic-gate GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 16237c478bd9Sstevel@tonic-gate size_t sym_size; 16247c478bd9Sstevel@tonic-gate caddr_t sp, ep; 16257c478bd9Sstevel@tonic-gate mdb_var_t *v; 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate if (gst == NULL) 16287c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&gst->gst_nv, file)) == NULL) 16317c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 16347c478bd9Sstevel@tonic-gate s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 16357c478bd9Sstevel@tonic-gate sym_size = sizeof (Elf32_Sym); 16367c478bd9Sstevel@tonic-gate } else { 16377c478bd9Sstevel@tonic-gate s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_to_sym; 16387c478bd9Sstevel@tonic-gate sym_size = sizeof (Elf64_Sym); 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate (void) s2gelf(mdb_nv_get_cookie(v), sym); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) != STT_FILE) 16447c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate ep = (caddr_t)gst->gst_dsect->gs_data + gst->gst_dsect->gs_shdr.sh_size; 16477c478bd9Sstevel@tonic-gate sp = (caddr_t)mdb_nv_get_cookie(v); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * We assume that symbol lookups scoped by source file name are only 16517c478bd9Sstevel@tonic-gate * relevant for userland debugging and are a relatively rare request, 16527c478bd9Sstevel@tonic-gate * and so we use a simple but inefficient linear search with copying. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate for (sp += sym_size; sp < ep; sp += sym_size) { 16557c478bd9Sstevel@tonic-gate (void) s2gelf(sp, sym); /* Convert native symbol to GElf */ 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_SECTION || 16587c478bd9Sstevel@tonic-gate GELF_ST_TYPE(sym->st_info) == STT_FILE || 16597c478bd9Sstevel@tonic-gate GELF_ST_BIND(sym->st_info) != STB_LOCAL) 16607c478bd9Sstevel@tonic-gate break; /* End of this file's locals */ 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate if (strcmp(mdb_gelf_sym_name(gst, sym), name) == 0) { 16637c478bd9Sstevel@tonic-gate if (idp != NULL) { 16647c478bd9Sstevel@tonic-gate *idp = (sp - (caddr_t) 16657c478bd9Sstevel@tonic-gate gst->gst_dsect->gs_data) / sym_size; 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate return (0); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate void 16757c478bd9Sstevel@tonic-gate mdb_gelf_symtab_iter(mdb_gelf_symtab_t *gst, int (*func)(void *, 16767c478bd9Sstevel@tonic-gate const GElf_Sym *, const char *, uint_t), void *private) 16777c478bd9Sstevel@tonic-gate { 16787c478bd9Sstevel@tonic-gate GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 16797c478bd9Sstevel@tonic-gate GElf_Sym sym, *symp; 16807c478bd9Sstevel@tonic-gate size_t sym_size; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 16837c478bd9Sstevel@tonic-gate s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 16847c478bd9Sstevel@tonic-gate sym_size = sizeof (Elf32_Sym); 16857c478bd9Sstevel@tonic-gate } else { 16867c478bd9Sstevel@tonic-gate s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_nocopy; 16877c478bd9Sstevel@tonic-gate sym_size = sizeof (Elf64_Sym); 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate /* 16917c478bd9Sstevel@tonic-gate * If this is a mutable symbol table, we iterate over the hash table 16927c478bd9Sstevel@tonic-gate * of symbol names; otherwise we go iterate over the data buffer. For 16937c478bd9Sstevel@tonic-gate * non-mutable tables, this means that ::nm will show all symbols, 16947c478bd9Sstevel@tonic-gate * including those with duplicate names (not present in gst_nv). 16957c478bd9Sstevel@tonic-gate */ 16967c478bd9Sstevel@tonic-gate if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 16977c478bd9Sstevel@tonic-gate mdb_gelf_dsym_t *dsp; 16987c478bd9Sstevel@tonic-gate mdb_var_t *v; 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate mdb_nv_rewind(&gst->gst_nv); 17017c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 17027c478bd9Sstevel@tonic-gate dsp = mdb_nv_get_cookie(v); 17037c478bd9Sstevel@tonic-gate symp = s2gelf(dsp, &sym); 17047c478bd9Sstevel@tonic-gate if (func(private, symp, mdb_nv_get_name(v), 17057c478bd9Sstevel@tonic-gate dsp->ds_id) == -1) 17067c478bd9Sstevel@tonic-gate break; 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate } else { 17107c478bd9Sstevel@tonic-gate const char *sbase = gst->gst_ssect->gs_data; 17117c478bd9Sstevel@tonic-gate caddr_t sp = gst->gst_dsect->gs_data; 17127c478bd9Sstevel@tonic-gate caddr_t ep = sp + gst->gst_dsect->gs_shdr.sh_size; 17137c478bd9Sstevel@tonic-gate uint_t i; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate for (i = 0; sp < ep; sp += sym_size, i++) { 17167c478bd9Sstevel@tonic-gate symp = s2gelf(sp, &sym); 17177c478bd9Sstevel@tonic-gate if (func(private, symp, sbase + symp->st_name, i) == -1) 17187c478bd9Sstevel@tonic-gate break; 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate static void 17247c478bd9Sstevel@tonic-gate gelf_sym_to_32(const GElf_Sym *src, Elf32_Sym *dst) 17257c478bd9Sstevel@tonic-gate { 17267c478bd9Sstevel@tonic-gate dst->st_name = src->st_name; 17277c478bd9Sstevel@tonic-gate dst->st_info = src->st_info; 17287c478bd9Sstevel@tonic-gate dst->st_other = src->st_other; 17297c478bd9Sstevel@tonic-gate dst->st_shndx = src->st_shndx; 17307c478bd9Sstevel@tonic-gate dst->st_value = (Elf32_Addr)src->st_value; 17317c478bd9Sstevel@tonic-gate dst->st_size = (Elf32_Word)src->st_size; 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate static void 17357c478bd9Sstevel@tonic-gate gelf_sym_to_64(const GElf_Sym *src, Elf64_Sym *dst) 17367c478bd9Sstevel@tonic-gate { 17377c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (Elf64_Sym)); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate void 17417c478bd9Sstevel@tonic-gate mdb_gelf_symtab_insert(mdb_gelf_symtab_t *gst, 17427c478bd9Sstevel@tonic-gate const char *name, const GElf_Sym *symp) 17437c478bd9Sstevel@tonic-gate { 17447c478bd9Sstevel@tonic-gate mdb_gelf_dsym_t *dsp; 17457c478bd9Sstevel@tonic-gate mdb_var_t *v; 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 17487c478bd9Sstevel@tonic-gate v = mdb_nv_lookup(&gst->gst_nv, name); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate if (v == NULL) { 17517c478bd9Sstevel@tonic-gate char *s = mdb_alloc(strlen(name) + 1, UM_SLEEP); 17527c478bd9Sstevel@tonic-gate (void) strcpy(s, name); 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate dsp = mdb_alloc(sizeof (mdb_gelf_dsym_t), UM_SLEEP); 17557c478bd9Sstevel@tonic-gate dsp->ds_id = gst->gst_id++; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate dsp->ds_var = mdb_nv_insert(&gst->gst_nv, s, NULL, 17587c478bd9Sstevel@tonic-gate (uintptr_t)dsp, GST_NVFLG); 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate gst->gst_aslen++; 17617c478bd9Sstevel@tonic-gate ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate if (gst->gst_aslen > gst->gst_asrsv) { 17647c478bd9Sstevel@tonic-gate mdb_free(gst->gst_asmap, 17657c478bd9Sstevel@tonic-gate sizeof (void *) * gst->gst_asrsv); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate gst->gst_asrsv = gst->gst_asrsv != 0 ? 17687c478bd9Sstevel@tonic-gate gst->gst_asrsv * GST_GROW : GST_DEFSZ; 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate gst->gst_asmap = mdb_alloc(sizeof (void *) * 17717c478bd9Sstevel@tonic-gate gst->gst_asrsv, UM_SLEEP); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate } else 17747c478bd9Sstevel@tonic-gate dsp = mdb_nv_get_cookie(v); 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "added symbol (\"%s\", %llx)\n", 17777c478bd9Sstevel@tonic-gate name, (u_longlong_t)symp->st_value); 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate bcopy(symp, &dsp->ds_sym, sizeof (GElf_Sym)); 17807c478bd9Sstevel@tonic-gate dsp->ds_sym.st_name = (uintptr_t)mdb_nv_get_name(dsp->ds_var); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 17837c478bd9Sstevel@tonic-gate gelf_sym_to_32(symp, &dsp->ds_u.ds_s32); 17847c478bd9Sstevel@tonic-gate gelf32_symtab_sort(gst); 17857c478bd9Sstevel@tonic-gate } else { 17867c478bd9Sstevel@tonic-gate gelf_sym_to_64(symp, &dsp->ds_u.ds_s64); 17877c478bd9Sstevel@tonic-gate gelf64_symtab_sort(gst); 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate void 17927c478bd9Sstevel@tonic-gate mdb_gelf_symtab_delete(mdb_gelf_symtab_t *gst, 17937c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *symp) 17947c478bd9Sstevel@tonic-gate { 17957c478bd9Sstevel@tonic-gate mdb_var_t *v; 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 17987c478bd9Sstevel@tonic-gate v = mdb_nv_lookup(&gst->gst_nv, name); 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate if (v != NULL) { 18017c478bd9Sstevel@tonic-gate char *name = (char *)mdb_nv_get_name(v); 18027c478bd9Sstevel@tonic-gate mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate if (symp != NULL) 18057c478bd9Sstevel@tonic-gate bcopy(&dsp->ds_sym, symp, sizeof (GElf_Sym)); 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_ELF, "removed symbol (\"%s\", %llx)\n", 18087c478bd9Sstevel@tonic-gate name, (u_longlong_t)dsp->ds_sym.st_value); 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate mdb_nv_remove(&gst->gst_nv, v); 18117c478bd9Sstevel@tonic-gate gst->gst_aslen--; 18127c478bd9Sstevel@tonic-gate ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 18157c478bd9Sstevel@tonic-gate mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 18187c478bd9Sstevel@tonic-gate gelf32_symtab_sort(gst); 18197c478bd9Sstevel@tonic-gate else 18207c478bd9Sstevel@tonic-gate gelf64_symtab_sort(gst); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate static const GElf_Phdr * 18257c478bd9Sstevel@tonic-gate gelf_phdr_lookup(mdb_gelf_file_t *gf, uintptr_t addr) 18267c478bd9Sstevel@tonic-gate { 18277c478bd9Sstevel@tonic-gate const GElf_Phdr *gpp = gf->gf_phdrs; 18287c478bd9Sstevel@tonic-gate GElf_Half i; 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate for (i = 0; i < gf->gf_npload; i++, gpp++) { 18317c478bd9Sstevel@tonic-gate if (addr >= gpp->p_vaddr && addr < gpp->p_vaddr + gpp->p_memsz) 18327c478bd9Sstevel@tonic-gate return (gpp); 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate return (NULL); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate ssize_t 18397c478bd9Sstevel@tonic-gate mdb_gelf_rw(mdb_gelf_file_t *gf, void *buf, size_t nbytes, uintptr_t addr, 18407c478bd9Sstevel@tonic-gate ssize_t (*prw)(mdb_io_t *, void *, size_t), mdb_gelf_rw_t rw) 18417c478bd9Sstevel@tonic-gate { 18427c478bd9Sstevel@tonic-gate ssize_t resid = nbytes; 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate while (resid != 0) { 18457c478bd9Sstevel@tonic-gate const GElf_Phdr *php = gelf_phdr_lookup(gf, addr); 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate uintptr_t mapoff; 18487c478bd9Sstevel@tonic-gate ssize_t memlen, filelen, len = 0; 18497c478bd9Sstevel@tonic-gate off64_t off; 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate if (php == NULL) 18527c478bd9Sstevel@tonic-gate break; /* No mapping for this address */ 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate mapoff = addr - php->p_vaddr; 18557c478bd9Sstevel@tonic-gate memlen = MIN(resid, php->p_memsz - mapoff); 18567c478bd9Sstevel@tonic-gate filelen = MIN(resid, php->p_filesz - mapoff); 18577c478bd9Sstevel@tonic-gate off = (off64_t)php->p_offset + mapoff; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate if (filelen > 0 && (IOP_SEEK(gf->gf_io, off, SEEK_SET) != off || 18607c478bd9Sstevel@tonic-gate (len = prw(gf->gf_io, buf, filelen)) <= 0)) 18617c478bd9Sstevel@tonic-gate break; 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate if (rw == GIO_READ && len == filelen && filelen < memlen) { 18647c478bd9Sstevel@tonic-gate bzero((char *)buf + len, memlen - filelen); 18657c478bd9Sstevel@tonic-gate len += memlen - filelen; 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate resid -= len; 18697c478bd9Sstevel@tonic-gate addr += len; 18707c478bd9Sstevel@tonic-gate buf = (char *)buf + len; 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate if (resid == nbytes && nbytes != 0) 18747c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate return (nbytes - resid); 18777c478bd9Sstevel@tonic-gate } 1878*a576ab5bSrab 1879*a576ab5bSrab mdb_gelf_sect_t * 1880*a576ab5bSrab mdb_gelf_sect_by_name(mdb_gelf_file_t *gf, const char *name) 1881*a576ab5bSrab { 1882*a576ab5bSrab int i; 1883*a576ab5bSrab 1884*a576ab5bSrab for (i = 0; i < gf->gf_shnum; i++) { 1885*a576ab5bSrab if (strcmp(gf->gf_sects[i].gs_name, name) == 0) 1886*a576ab5bSrab return (&gf->gf_sects[i]); 1887*a576ab5bSrab } 1888*a576ab5bSrab 1889*a576ab5bSrab return (NULL); 1890*a576ab5bSrab } 1891