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