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