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