1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/isa_defs.h> 27 #include <sys/link.h> 28 #include <strings.h> 29 #include <stdlib.h> 30 31 #include <mdb/mdb_debug.h> 32 #include <mdb/mdb_modapi.h> 33 #include <mdb/mdb_io_impl.h> 34 #include <mdb/mdb_gelf.h> 35 #include <mdb/mdb_err.h> 36 #include <mdb/mdb.h> 37 38 #define GST_GROW 2 /* Mutable symbol table growth multiplier */ 39 #define GST_DEFSZ 16 /* Mutable symbol table initial size */ 40 41 #define GST_NVFLG (MDB_NV_EXTNAME | MDB_NV_SILENT) 42 43 static const char *gelf_strtab; /* Active string table for qsort callbacks */ 44 45 static mdb_gelf_file_t * 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 #if STT_NUM != (STT_TLS + 1) 931 #error "STT_NUM has grown. update gelf32_symtab_init()" 932 #endif 933 934 const char *base = (const char *)gst->gst_ssect->gs_data; 935 Elf32_Sym *sym = gst->gst_dsect->gs_data; 936 mdb_nv_t *nv = &gst->gst_nv; 937 938 Elf32_Word ss_size = gst->gst_ssect->gs_shdr.sh_size; 939 size_t asrsv = 0; 940 GElf_Word i, n; 941 942 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf32_Sym)) { 943 warn("%s sh_entsize %llu != sizeof (Elf32_Sym); " 944 "using %u instead\n", gst->gst_dsect->gs_name, 945 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 946 (uint_t)sizeof (Elf32_Sym)); 947 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf32_Sym); 948 } 949 950 n = gst->gst_dsect->gs_shdr.sh_size / 951 gst->gst_dsect->gs_shdr.sh_entsize; 952 953 for (i = 0; i < n; i++, sym++) { 954 const char *name = base + sym->st_name; 955 uchar_t type = ELF32_ST_TYPE(sym->st_info); 956 957 if (type >= STT_NUM || type == STT_SECTION) 958 continue; /* skip sections and unknown types */ 959 960 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 961 if (sym->st_name >= ss_size || name[0] != '\0') { 962 warn("ignoring %s symbol [%u]: invalid name\n", 963 gst->gst_dsect->gs_name, i); 964 sym->st_name = 0; 965 } 966 continue; /* skip corrupt or empty names */ 967 } 968 969 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 970 971 if (sym->st_value != 0 && 972 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 973 asrsv++; /* reserve space in the address map */ 974 } 975 976 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 977 GElf_Word smax = gst->gst_file->gf_shnum; 978 mdb_gelf_sect_t *gsp; 979 980 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 981 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 982 gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 983 sym->st_value += gsp->gs_shdr.sh_offset; 984 985 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || 986 sym->st_size != 0) 987 asrsv++; /* reserve space in asmap */ 988 } 989 } 990 } 991 992 gst->gst_asmap = mdb_alloc(sizeof (Elf32_Sym *) * asrsv, UM_SLEEP); 993 gst->gst_asrsv = asrsv; 994 995 gelf32_symtab_sort(gst); 996 } 997 998 static void 999 gelf64_symtab_sort(mdb_gelf_symtab_t *gst) 1000 { 1001 Elf64_Sym **sympp = (Elf64_Sym **)gst->gst_asmap; 1002 mdb_var_t *v; 1003 1004 mdb_nv_rewind(&gst->gst_nv); 1005 1006 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 1007 Elf64_Sym *sym = MDB_NV_COOKIE(v); 1008 if (sym->st_value != 0 && 1009 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 1010 *sympp++ = sym; 1011 } 1012 1013 gst->gst_aslen = (size_t)(sympp - (Elf64_Sym **)gst->gst_asmap); 1014 ASSERT(gst->gst_aslen <= gst->gst_asrsv); 1015 1016 gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL; 1017 1018 qsort(gst->gst_asmap, gst->gst_aslen, 1019 sizeof (Elf64_Sym *), gelf64_sym_compare); 1020 1021 gelf_strtab = NULL; 1022 } 1023 1024 static void 1025 gelf64_symtab_init(mdb_gelf_symtab_t *gst) 1026 { 1027 #if STT_NUM != (STT_TLS + 1) 1028 #error "STT_NUM has grown. update gelf64_symtab_init()" 1029 #endif 1030 1031 const char *base = (const char *)gst->gst_ssect->gs_data; 1032 Elf64_Sym *sym = gst->gst_dsect->gs_data; 1033 mdb_nv_t *nv = &gst->gst_nv; 1034 1035 Elf64_Xword ss_size = gst->gst_ssect->gs_shdr.sh_size; 1036 size_t asrsv = 0; 1037 GElf_Word i, n; 1038 1039 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf64_Sym)) { 1040 warn("%s sh_entsize %llu != sizeof (Elf64_Sym); " 1041 "using %u instead\n", gst->gst_dsect->gs_name, 1042 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 1043 (uint_t)sizeof (Elf64_Sym)); 1044 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf64_Sym); 1045 } 1046 1047 n = gst->gst_dsect->gs_shdr.sh_size / 1048 gst->gst_dsect->gs_shdr.sh_entsize; 1049 1050 for (i = 0; i < n; i++, sym++) { 1051 const char *name = base + sym->st_name; 1052 uchar_t type = ELF64_ST_TYPE(sym->st_info); 1053 1054 if (type >= STT_NUM || type == STT_SECTION) 1055 continue; /* skip sections and unknown types */ 1056 1057 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 1058 if (sym->st_name >= ss_size || name[0] != '\0') { 1059 warn("ignoring %s symbol [%u]: invalid name\n", 1060 gst->gst_dsect->gs_name, i); 1061 sym->st_name = 0; 1062 } 1063 continue; /* skip corrupt or empty names */ 1064 } 1065 1066 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 1067 1068 if (sym->st_value != 0 && 1069 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 1070 asrsv++; /* reserve space in the address map */ 1071 } 1072 1073 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 1074 GElf_Word smax = gst->gst_file->gf_shnum; 1075 mdb_gelf_sect_t *gsp; 1076 1077 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 1078 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 1079 gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 1080 sym->st_value += gsp->gs_shdr.sh_offset; 1081 1082 if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || 1083 sym->st_size != 0) 1084 asrsv++; /* reserve space in asmap */ 1085 } 1086 } 1087 } 1088 1089 gst->gst_asmap = mdb_alloc(sizeof (Elf64_Sym *) * asrsv, UM_SLEEP); 1090 gst->gst_asrsv = asrsv; 1091 1092 gelf64_symtab_sort(gst); 1093 } 1094 1095 mdb_gelf_symtab_t * 1096 mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype, 1097 uint_t tabid) 1098 { 1099 mdb_gelf_sect_t *gsp; 1100 const char *dsname = NULL; 1101 const char *ssname; 1102 size_t i; 1103 GElf_Word link; 1104 1105 /* 1106 * Examine the sh_link field in the the Elf header to get the name 1107 * of the corresponding strings section 1108 */ 1109 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 1110 if (gsp->gs_shdr.sh_type == elftype) { 1111 dsname = gsp->gs_name; 1112 link = gsp->gs_shdr.sh_link; 1113 break; 1114 } 1115 } 1116 1117 if (dsname == NULL) 1118 return (NULL); 1119 1120 if (link > gf->gf_shnum) { 1121 /* 1122 * Invalid link number due to corrupt elf file. 1123 */ 1124 warn("link number %ud larger than number of sections %d\n", 1125 link, gf->gf_shnum); 1126 return (NULL); 1127 } 1128 1129 ssname = (gf->gf_sects + link)->gs_name; 1130 1131 return (mdb_gelf_symtab_create_file_by_name(gf, dsname, ssname, tabid)); 1132 } 1133 1134 mdb_gelf_symtab_t * 1135 mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf, 1136 const char *dsname, const char *ssname, uint_t tabid) 1137 { 1138 mdb_gelf_symtab_t *gst; 1139 mdb_gelf_sect_t *gsp; 1140 size_t i; 1141 1142 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1143 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1144 1145 gst->gst_asmap = NULL; 1146 gst->gst_aslen = 0; 1147 gst->gst_asrsv = 0; 1148 gst->gst_ehdr = &gf->gf_ehdr; 1149 gst->gst_file = gf; 1150 gst->gst_dsect = NULL; 1151 gst->gst_ssect = NULL; 1152 gst->gst_id = 0; 1153 gst->gst_tabid = tabid; 1154 1155 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 1156 if (strcmp(gsp->gs_name, dsname) == 0) { 1157 gst->gst_dsect = gsp; 1158 break; 1159 } 1160 } 1161 1162 for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { 1163 if (strcmp(gsp->gs_name, ssname) == 0) { 1164 gst->gst_ssect = gsp; 1165 break; 1166 } 1167 } 1168 1169 if (gst->gst_dsect == NULL || gst->gst_ssect == NULL) 1170 goto err; /* Failed to locate data or string section */ 1171 1172 if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL) 1173 goto err; /* Failed to load data section */ 1174 1175 if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL) 1176 goto err; /* Failed to load string section */ 1177 1178 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 1179 gelf32_symtab_init(gst); 1180 else 1181 gelf64_symtab_init(gst); 1182 1183 return (gst); 1184 1185 err: 1186 mdb_nv_destroy(&gst->gst_nv); 1187 mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 1188 return (NULL); 1189 } 1190 1191 mdb_gelf_symtab_t * 1192 mdb_gelf_symtab_create_raw(const GElf_Ehdr *ehdr, const void *dshdr, 1193 void *ddata, const void *sshdr, void *sdata, uint_t tabid) 1194 { 1195 mdb_gelf_symtab_t *gst; 1196 1197 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1198 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1199 1200 gst->gst_asmap = NULL; 1201 gst->gst_aslen = 0; 1202 gst->gst_asrsv = 0; 1203 gst->gst_ehdr = ehdr; 1204 gst->gst_file = NULL; /* Flag for raw symtab */ 1205 gst->gst_id = 0; 1206 gst->gst_tabid = tabid; 1207 1208 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1209 gst->gst_dsect->gs_name = ".symtab"; 1210 gst->gst_dsect->gs_data = ddata; 1211 1212 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1213 gst->gst_ssect->gs_name = ".strtab"; 1214 gst->gst_ssect->gs_data = sdata; 1215 1216 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1217 (void) gelf32_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 1218 (void) gelf32_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 1219 gelf32_symtab_init(gst); 1220 } else { 1221 (void) gelf64_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 1222 (void) gelf64_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 1223 gelf64_symtab_init(gst); 1224 } 1225 1226 return (gst); 1227 } 1228 1229 mdb_gelf_symtab_t * 1230 mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t *gf, uint_t tabid) 1231 { 1232 GElf_Addr dt_symtab, dt_strtab, dt_hash; 1233 GElf_Xword dt_syment, dt_strsz; 1234 1235 mdb_gelf_symtab_t *gst; 1236 uint_t hash_h[2]; 1237 off64_t base = 0; 1238 1239 ASSERT(gf->gf_mode == GF_PROGRAM); 1240 1241 /* 1242 * Read in and cache the array of GElf_Dyn structures from the 1243 * PT_DYNAMIC phdr. Abort if this is not possible. 1244 */ 1245 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1246 (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn), 1247 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn); 1248 } else { 1249 (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn), 1250 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn); 1251 } 1252 1253 /* 1254 * Pre-fetch all the DT_* entries we will need for creating the 1255 * dynamic symbol table; abort if any are missing. 1256 */ 1257 if ((dt_hash = gelf_dyn_lookup(gf, DT_HASH)) == -1L) { 1258 warn("failed to get DT_HASH for %s\n", IOP_NAME(gf->gf_io)); 1259 return (NULL); 1260 } 1261 1262 if ((dt_symtab = gelf_dyn_lookup(gf, DT_SYMTAB)) == -1L) { 1263 warn("failed to get DT_SYMTAB for %s\n", IOP_NAME(gf->gf_io)); 1264 return (NULL); 1265 } 1266 1267 if ((dt_syment = gelf_dyn_lookup(gf, DT_SYMENT)) == -1L) { 1268 warn("failed to get DT_SYMENT for %s\n", IOP_NAME(gf->gf_io)); 1269 return (NULL); 1270 } 1271 1272 if ((dt_strtab = gelf_dyn_lookup(gf, DT_STRTAB)) == -1L) { 1273 warn("failed to get DT_STRTAB for %s\n", IOP_NAME(gf->gf_io)); 1274 return (NULL); 1275 } 1276 1277 if ((dt_strsz = gelf_dyn_lookup(gf, DT_STRSZ)) == -1L) { 1278 warn("failed to get DT_STRSZ for %s\n", IOP_NAME(gf->gf_io)); 1279 return (NULL); 1280 } 1281 1282 /* 1283 * If this is an executable, then DT_HASH is an absolute address; 1284 * we need to subtract the virtual base address of the mapping. 1285 */ 1286 if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0) 1287 base = (off64_t)gf->gf_phdrs->p_vaddr; 1288 1289 /* 1290 * Read in the header for the DT_HASH: this consists of nbucket 1291 * and nchain values (nchain is the number of hashed symbols). 1292 */ 1293 if (IOP_SEEK(gf->gf_io, (off64_t)dt_hash - base, SEEK_SET) == -1) { 1294 warn("failed to seek ELF file to start of DT_HASH"); 1295 return (NULL); 1296 } 1297 1298 if (IOP_READ(gf->gf_io, hash_h, sizeof (hash_h)) != sizeof (hash_h)) { 1299 warn("failed to read DT_HASH header"); 1300 return (NULL); 1301 } 1302 1303 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1304 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1305 1306 gst->gst_asmap = NULL; 1307 gst->gst_aslen = 0; 1308 gst->gst_asrsv = 0; 1309 gst->gst_ehdr = &gf->gf_ehdr; 1310 gst->gst_file = gf; 1311 gst->gst_id = 0; 1312 gst->gst_tabid = tabid; 1313 1314 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1315 gst->gst_dsect->gs_name = ".dynsym"; 1316 gst->gst_dsect->gs_shdr.sh_offset = dt_symtab - (GElf_Addr)base; 1317 gst->gst_dsect->gs_shdr.sh_size = hash_h[1] * dt_syment; 1318 gst->gst_dsect->gs_shdr.sh_entsize = dt_syment; 1319 1320 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1321 gst->gst_ssect->gs_name = ".dynstr"; 1322 gst->gst_ssect->gs_shdr.sh_offset = dt_strtab - (GElf_Addr)base; 1323 gst->gst_ssect->gs_shdr.sh_size = dt_strsz; 1324 gst->gst_ssect->gs_shdr.sh_entsize = 0; 1325 1326 if (mdb_gelf_sect_load(gf, gst->gst_dsect) == NULL) 1327 goto err; 1328 1329 if (mdb_gelf_sect_load(gf, gst->gst_ssect) == NULL) 1330 goto err; 1331 1332 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 1333 gelf32_symtab_init(gst); 1334 else 1335 gelf64_symtab_init(gst); 1336 1337 return (gst); 1338 1339 err: 1340 mdb_gelf_symtab_destroy(gst); 1341 return (NULL); 1342 } 1343 1344 mdb_gelf_symtab_t * 1345 mdb_gelf_symtab_create_mutable(void) 1346 { 1347 mdb_gelf_symtab_t *gst; 1348 static GElf_Ehdr ehdr; 1349 1350 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1351 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1352 gst->gst_ehdr = &ehdr; 1353 1354 if (ehdr.e_version == 0) { 1355 #ifdef _LP64 1356 uchar_t class = ELFCLASS64; 1357 #else 1358 uchar_t class = ELFCLASS32; 1359 #endif 1360 1361 #ifdef _BIG_ENDIAN 1362 uchar_t data = ELFDATA2MSB; 1363 #else 1364 uchar_t data = ELFDATA2LSB; 1365 #endif 1366 /* 1367 * Since all mutable symbol tables will use a native Ehdr, 1368 * we can just have a single static copy which they all 1369 * point to and we only need initialize once. 1370 */ 1371 ehdr.e_ident[EI_MAG0] = ELFMAG0; 1372 ehdr.e_ident[EI_MAG1] = ELFMAG1; 1373 ehdr.e_ident[EI_MAG2] = ELFMAG2; 1374 ehdr.e_ident[EI_MAG3] = ELFMAG3; 1375 ehdr.e_ident[EI_CLASS] = class; 1376 ehdr.e_ident[EI_DATA] = data; 1377 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 1378 ehdr.e_type = ET_NONE; 1379 ehdr.e_version = EV_CURRENT; 1380 } 1381 1382 return (gst); 1383 } 1384 1385 void 1386 mdb_gelf_symtab_destroy(mdb_gelf_symtab_t *gst) 1387 { 1388 if (gst->gst_file == NULL) { 1389 if (gst->gst_dsect == NULL && gst->gst_ssect == NULL) { 1390 mdb_var_t *v; 1391 1392 mdb_nv_rewind(&gst->gst_nv); 1393 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 1394 char *name = (char *)mdb_nv_get_name(v); 1395 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1396 1397 mdb_free(name, strlen(name) + 1); 1398 mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 1399 } 1400 1401 } else { 1402 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 1403 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 1404 } 1405 1406 } else if (gst->gst_file->gf_mode == GF_PROGRAM) { 1407 mdb_gelf_sect_t *dsect = gst->gst_dsect; 1408 mdb_gelf_sect_t *ssect = gst->gst_ssect; 1409 1410 if (dsect->gs_data != NULL) 1411 mdb_free(dsect->gs_data, dsect->gs_shdr.sh_size); 1412 if (ssect->gs_data != NULL) 1413 mdb_free(ssect->gs_data, ssect->gs_shdr.sh_size); 1414 1415 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 1416 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 1417 } 1418 1419 mdb_nv_destroy(&gst->gst_nv); 1420 mdb_free(gst->gst_asmap, gst->gst_asrsv * sizeof (void *)); 1421 mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 1422 } 1423 1424 size_t 1425 mdb_gelf_symtab_size(mdb_gelf_symtab_t *gst) 1426 { 1427 return (mdb_nv_size(&gst->gst_nv)); 1428 } 1429 1430 static GElf_Sym * 1431 gelf32_to_sym(const Elf32_Sym *src, GElf_Sym *dst) 1432 { 1433 if (src != NULL) { 1434 dst->st_name = src->st_name; 1435 dst->st_info = src->st_info; 1436 dst->st_other = src->st_other; 1437 dst->st_shndx = src->st_shndx; 1438 dst->st_value = src->st_value; 1439 dst->st_size = src->st_size; 1440 return (dst); 1441 } 1442 1443 return (NULL); 1444 } 1445 1446 static GElf_Sym * 1447 gelf64_to_sym(const Elf64_Sym *src, GElf_Sym *dst) 1448 { 1449 if (src != NULL) { 1450 bcopy(src, dst, sizeof (GElf_Sym)); 1451 return (dst); 1452 } 1453 1454 return (NULL); 1455 } 1456 1457 /*ARGSUSED*/ 1458 static GElf_Sym * 1459 gelf64_nocopy(const Elf64_Sym *src, GElf_Sym *dst) 1460 { 1461 return ((GElf_Sym *)src); 1462 } 1463 1464 static const void * 1465 gelf32_sym_search(const Elf32_Sym **asmap, size_t aslen, uintptr_t addr) 1466 { 1467 ulong_t i, mid, lo = 0, hi = aslen - 1; 1468 const Elf32_Sym *symp; 1469 Elf32_Addr v; 1470 size_t size; 1471 1472 if (aslen == 0) 1473 return (NULL); 1474 1475 while (hi - lo > 1) { 1476 mid = (lo + hi) / 2; 1477 if (addr >= asmap[mid]->st_value) 1478 lo = mid; 1479 else 1480 hi = mid; 1481 } 1482 1483 i = addr < asmap[hi]->st_value ? lo : hi; 1484 symp = asmap[i]; 1485 v = symp->st_value; 1486 1487 /* 1488 * If the previous entry has the same value, improve our choice. The 1489 * order of equal-valued symbols is determined by gelf32_sym_compare(). 1490 */ 1491 while (i-- != 0 && asmap[i]->st_value == v) 1492 symp = asmap[i]; 1493 1494 /* 1495 * If an absolute symbol distance was specified, use that; otherwise 1496 * use the ELF symbol size, or 1 byte if the ELF size is zero. 1497 */ 1498 if (mdb.m_symdist == 0) 1499 size = MAX(symp->st_size, 1); 1500 else 1501 size = mdb.m_symdist; 1502 1503 if (addr - symp->st_value < size) 1504 return (symp); 1505 1506 return (NULL); 1507 } 1508 1509 static const void * 1510 gelf64_sym_search(const Elf64_Sym **asmap, size_t aslen, uintptr_t addr) 1511 { 1512 ulong_t i, mid, lo = 0, hi = aslen - 1; 1513 const Elf64_Sym *symp; 1514 Elf64_Addr v; 1515 size_t size; 1516 1517 if (aslen == 0) 1518 return (NULL); 1519 1520 while (hi - lo > 1) { 1521 mid = (lo + hi) / 2; 1522 if (addr >= asmap[mid]->st_value) 1523 lo = mid; 1524 else 1525 hi = mid; 1526 } 1527 1528 i = addr < asmap[hi]->st_value ? lo : hi; 1529 symp = asmap[i]; 1530 v = symp->st_value; 1531 1532 /* 1533 * If the previous entry has the same value, improve our choice. The 1534 * order of equal-valued symbols is determined by gelf64_sym_compare(). 1535 */ 1536 while (i-- != 0 && asmap[i]->st_value == v) 1537 symp = asmap[i]; 1538 1539 /* 1540 * If an absolute symbol distance was specified, use that; otherwise 1541 * use the ELF symbol size, or 1 byte if the ELF size is zero. 1542 */ 1543 if (mdb.m_symdist == 0) 1544 size = MAX(symp->st_size, 1); 1545 else 1546 size = mdb.m_symdist; 1547 1548 if (addr - symp->st_value < size) 1549 return (symp); 1550 1551 return (NULL); 1552 } 1553 1554 const char * 1555 mdb_gelf_sym_name(mdb_gelf_symtab_t *gst, const GElf_Sym *sym) 1556 { 1557 const mdb_gelf_dsym_t *dsp; 1558 1559 if (gst->gst_ssect != NULL) 1560 return ((const char *)gst->gst_ssect->gs_data + sym->st_name); 1561 1562 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1563 dsp = gelf32_sym_search(gst->gst_asmap, 1564 gst->gst_aslen, sym->st_value); 1565 else 1566 dsp = gelf64_sym_search(gst->gst_asmap, 1567 gst->gst_aslen, sym->st_value); 1568 1569 if (dsp != NULL) 1570 return (mdb_nv_get_name(dsp->ds_var)); 1571 1572 return (NULL); 1573 } 1574 1575 int 1576 mdb_gelf_sym_closer(const GElf_Sym *s1, const GElf_Sym *s2, uintptr_t addr) 1577 { 1578 uintptr_t v1 = (uintptr_t)s1->st_value; 1579 uintptr_t v2 = (uintptr_t)s2->st_value; 1580 1581 uintptr_t d1 = v1 > addr ? v1 - addr : addr - v1; 1582 uintptr_t d2 = v2 > addr ? v2 - addr : addr - v2; 1583 1584 return (d1 < d2); 1585 } 1586 1587 int 1588 mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t *gst, uintptr_t addr, 1589 uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym, uint_t *idp) 1590 { 1591 union { 1592 const mdb_gelf_dsym_t *dsp; 1593 const Elf32_Sym *s32; 1594 const Elf64_Sym *s64; 1595 caddr_t sp; 1596 } u; 1597 1598 const char *name; 1599 1600 if (gst == NULL) 1601 return (set_errno(EMDB_NOSYMADDR)); 1602 1603 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1604 u.s32 = gelf32_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 1605 if (gelf32_to_sym(u.s32, sym) == NULL) 1606 return (set_errno(EMDB_NOSYMADDR)); 1607 } else { 1608 u.s64 = gelf64_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 1609 if (gelf64_to_sym(u.s64, sym) == NULL) 1610 return (set_errno(EMDB_NOSYMADDR)); 1611 } 1612 1613 if ((flags & GST_EXACT) && (sym->st_value != addr)) 1614 return (set_errno(EMDB_NOSYMADDR)); 1615 1616 if (gst->gst_ssect != NULL) { 1617 name = (const char *)gst->gst_ssect->gs_data + sym->st_name; 1618 if (idp != NULL) { 1619 *idp = (u.sp - (caddr_t)gst->gst_dsect->gs_data) / 1620 gst->gst_dsect->gs_shdr.sh_entsize; 1621 } 1622 } else { 1623 name = mdb_nv_get_name(u.dsp->ds_var); 1624 if (idp != NULL) 1625 *idp = u.dsp->ds_id; 1626 } 1627 1628 if (nbytes > 0) { 1629 (void) strncpy(buf, name, nbytes - 1); 1630 buf[nbytes - 1] = '\0'; 1631 } 1632 return (0); 1633 } 1634 1635 int 1636 mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t *gst, const char *name, 1637 GElf_Sym *sym, uint_t *idp) 1638 { 1639 mdb_var_t *v; 1640 1641 if (gst != NULL && (v = mdb_nv_lookup(&gst->gst_nv, name)) != NULL) { 1642 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1643 (void) gelf32_to_sym(mdb_nv_get_cookie(v), sym); 1644 else 1645 (void) gelf64_to_sym(mdb_nv_get_cookie(v), sym); 1646 1647 if (idp != NULL) { 1648 if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 1649 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1650 *idp = dsp->ds_id; 1651 } else { 1652 *idp = ((uintptr_t)mdb_nv_get_cookie(v) - 1653 (uintptr_t)gst->gst_dsect->gs_data) / 1654 gst->gst_dsect->gs_shdr.sh_entsize; 1655 } 1656 } 1657 1658 return (0); 1659 } 1660 1661 return (set_errno(EMDB_NOSYM)); 1662 } 1663 1664 int 1665 mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t *gst, const char *file, 1666 const char *name, GElf_Sym *sym, uint_t *idp) 1667 { 1668 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 1669 size_t sym_size; 1670 caddr_t sp, ep; 1671 mdb_var_t *v; 1672 1673 if (gst == NULL) 1674 return (set_errno(EMDB_NOSYM)); 1675 1676 if ((v = mdb_nv_lookup(&gst->gst_nv, file)) == NULL) 1677 return (set_errno(EMDB_NOOBJ)); 1678 1679 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1680 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 1681 sym_size = sizeof (Elf32_Sym); 1682 } else { 1683 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_to_sym; 1684 sym_size = sizeof (Elf64_Sym); 1685 } 1686 1687 (void) s2gelf(mdb_nv_get_cookie(v), sym); 1688 1689 if (GELF_ST_TYPE(sym->st_info) != STT_FILE) 1690 return (set_errno(EMDB_NOOBJ)); 1691 1692 ep = (caddr_t)gst->gst_dsect->gs_data + gst->gst_dsect->gs_shdr.sh_size; 1693 sp = (caddr_t)mdb_nv_get_cookie(v); 1694 1695 /* 1696 * We assume that symbol lookups scoped by source file name are only 1697 * relevant for userland debugging and are a relatively rare request, 1698 * and so we use a simple but inefficient linear search with copying. 1699 */ 1700 for (sp += sym_size; sp < ep; sp += sym_size) { 1701 (void) s2gelf(sp, sym); /* Convert native symbol to GElf */ 1702 1703 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION || 1704 GELF_ST_TYPE(sym->st_info) == STT_FILE || 1705 GELF_ST_BIND(sym->st_info) != STB_LOCAL) 1706 break; /* End of this file's locals */ 1707 1708 if (strcmp(mdb_gelf_sym_name(gst, sym), name) == 0) { 1709 if (idp != NULL) { 1710 *idp = (sp - (caddr_t) 1711 gst->gst_dsect->gs_data) / sym_size; 1712 } 1713 return (0); 1714 } 1715 } 1716 1717 return (set_errno(EMDB_NOSYM)); 1718 } 1719 1720 void 1721 mdb_gelf_symtab_iter(mdb_gelf_symtab_t *gst, int (*func)(void *, 1722 const GElf_Sym *, const char *, uint_t), void *private) 1723 { 1724 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 1725 GElf_Sym sym, *symp; 1726 size_t sym_size; 1727 1728 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1729 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 1730 sym_size = sizeof (Elf32_Sym); 1731 } else { 1732 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_nocopy; 1733 sym_size = sizeof (Elf64_Sym); 1734 } 1735 1736 /* 1737 * If this is a mutable symbol table, we iterate over the hash table 1738 * of symbol names; otherwise we go iterate over the data buffer. For 1739 * non-mutable tables, this means that ::nm will show all symbols, 1740 * including those with duplicate names (not present in gst_nv). 1741 */ 1742 if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 1743 mdb_gelf_dsym_t *dsp; 1744 mdb_var_t *v; 1745 1746 mdb_nv_rewind(&gst->gst_nv); 1747 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 1748 dsp = mdb_nv_get_cookie(v); 1749 symp = s2gelf(dsp, &sym); 1750 if (func(private, symp, mdb_nv_get_name(v), 1751 dsp->ds_id) == -1) 1752 break; 1753 } 1754 1755 } else { 1756 const char *sbase = gst->gst_ssect->gs_data; 1757 caddr_t sp = gst->gst_dsect->gs_data; 1758 caddr_t ep = sp + gst->gst_dsect->gs_shdr.sh_size; 1759 uint_t i; 1760 1761 for (i = 0; sp < ep; sp += sym_size, i++) { 1762 symp = s2gelf(sp, &sym); 1763 if (func(private, symp, sbase + symp->st_name, i) == -1) 1764 break; 1765 } 1766 } 1767 } 1768 1769 static void 1770 gelf_sym_to_32(const GElf_Sym *src, Elf32_Sym *dst) 1771 { 1772 dst->st_name = src->st_name; 1773 dst->st_info = src->st_info; 1774 dst->st_other = src->st_other; 1775 dst->st_shndx = src->st_shndx; 1776 dst->st_value = (Elf32_Addr)src->st_value; 1777 dst->st_size = (Elf32_Word)src->st_size; 1778 } 1779 1780 static void 1781 gelf_sym_to_64(const GElf_Sym *src, Elf64_Sym *dst) 1782 { 1783 bcopy(src, dst, sizeof (Elf64_Sym)); 1784 } 1785 1786 void 1787 mdb_gelf_symtab_insert(mdb_gelf_symtab_t *gst, 1788 const char *name, const GElf_Sym *symp) 1789 { 1790 mdb_gelf_dsym_t *dsp; 1791 mdb_var_t *v; 1792 1793 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 1794 v = mdb_nv_lookup(&gst->gst_nv, name); 1795 1796 if (v == NULL) { 1797 char *s = mdb_alloc(strlen(name) + 1, UM_SLEEP); 1798 (void) strcpy(s, name); 1799 1800 dsp = mdb_alloc(sizeof (mdb_gelf_dsym_t), UM_SLEEP); 1801 dsp->ds_id = gst->gst_id++; 1802 1803 dsp->ds_var = mdb_nv_insert(&gst->gst_nv, s, NULL, 1804 (uintptr_t)dsp, GST_NVFLG); 1805 1806 gst->gst_aslen++; 1807 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 1808 1809 if (gst->gst_aslen > gst->gst_asrsv) { 1810 mdb_free(gst->gst_asmap, 1811 sizeof (void *) * gst->gst_asrsv); 1812 1813 gst->gst_asrsv = gst->gst_asrsv != 0 ? 1814 gst->gst_asrsv * GST_GROW : GST_DEFSZ; 1815 1816 gst->gst_asmap = mdb_alloc(sizeof (void *) * 1817 gst->gst_asrsv, UM_SLEEP); 1818 } 1819 } else 1820 dsp = mdb_nv_get_cookie(v); 1821 1822 mdb_dprintf(MDB_DBG_ELF, "added symbol (\"%s\", %llx)\n", 1823 name, (u_longlong_t)symp->st_value); 1824 1825 bcopy(symp, &dsp->ds_sym, sizeof (GElf_Sym)); 1826 dsp->ds_sym.st_name = (uintptr_t)mdb_nv_get_name(dsp->ds_var); 1827 1828 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1829 gelf_sym_to_32(symp, &dsp->ds_u.ds_s32); 1830 gelf32_symtab_sort(gst); 1831 } else { 1832 gelf_sym_to_64(symp, &dsp->ds_u.ds_s64); 1833 gelf64_symtab_sort(gst); 1834 } 1835 } 1836 1837 void 1838 mdb_gelf_symtab_delete(mdb_gelf_symtab_t *gst, 1839 const char *name, GElf_Sym *symp) 1840 { 1841 mdb_var_t *v; 1842 1843 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 1844 v = mdb_nv_lookup(&gst->gst_nv, name); 1845 1846 if (v != NULL) { 1847 char *name = (char *)mdb_nv_get_name(v); 1848 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1849 1850 if (symp != NULL) 1851 bcopy(&dsp->ds_sym, symp, sizeof (GElf_Sym)); 1852 1853 mdb_dprintf(MDB_DBG_ELF, "removed symbol (\"%s\", %llx)\n", 1854 name, (u_longlong_t)dsp->ds_sym.st_value); 1855 1856 mdb_nv_remove(&gst->gst_nv, v); 1857 gst->gst_aslen--; 1858 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 1859 1860 mdb_free(name, strlen(name) + 1); 1861 mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 1862 1863 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1864 gelf32_symtab_sort(gst); 1865 else 1866 gelf64_symtab_sort(gst); 1867 } 1868 } 1869 1870 static const GElf_Phdr * 1871 gelf_phdr_lookup(mdb_gelf_file_t *gf, uintptr_t addr) 1872 { 1873 const GElf_Phdr *gpp = gf->gf_phdrs; 1874 size_t i; 1875 1876 for (i = 0; i < gf->gf_npload; i++, gpp++) { 1877 if (addr >= gpp->p_vaddr && addr < gpp->p_vaddr + gpp->p_memsz) 1878 return (gpp); 1879 } 1880 1881 return (NULL); 1882 } 1883 1884 ssize_t 1885 mdb_gelf_rw(mdb_gelf_file_t *gf, void *buf, size_t nbytes, uintptr_t addr, 1886 ssize_t (*prw)(mdb_io_t *, void *, size_t), mdb_gelf_rw_t rw) 1887 { 1888 ssize_t resid = nbytes; 1889 1890 while (resid != 0) { 1891 const GElf_Phdr *php = gelf_phdr_lookup(gf, addr); 1892 1893 uintptr_t mapoff; 1894 ssize_t memlen, filelen, len = 0; 1895 off64_t off; 1896 1897 if (php == NULL) 1898 break; /* No mapping for this address */ 1899 1900 mapoff = addr - php->p_vaddr; 1901 memlen = MIN(resid, php->p_memsz - mapoff); 1902 filelen = MIN(resid, php->p_filesz - mapoff); 1903 off = (off64_t)php->p_offset + mapoff; 1904 1905 if (filelen > 0 && (IOP_SEEK(gf->gf_io, off, SEEK_SET) != off || 1906 (len = prw(gf->gf_io, buf, filelen)) <= 0)) 1907 break; 1908 1909 if (rw == GIO_READ && len == filelen && filelen < memlen) { 1910 bzero((char *)buf + len, memlen - filelen); 1911 len += memlen - filelen; 1912 } 1913 1914 resid -= len; 1915 addr += len; 1916 buf = (char *)buf + len; 1917 } 1918 1919 if (resid == nbytes && nbytes != 0) 1920 return (set_errno(EMDB_NOMAP)); 1921 1922 return (nbytes - resid); 1923 } 1924 1925 mdb_gelf_sect_t * 1926 mdb_gelf_sect_by_name(mdb_gelf_file_t *gf, const char *name) 1927 { 1928 size_t i; 1929 1930 for (i = 0; i < gf->gf_shnum; i++) { 1931 if (strcmp(gf->gf_sects[i].gs_name, name) == 0) 1932 return (&gf->gf_sects[i]); 1933 } 1934 1935 return (NULL); 1936 } 1937