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 2004 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_ehdr.e_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_ehdr.e_shnum = 0; /* Simplifies other code paths */ 58 59 if (gf->gf_ehdr.e_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_ehdr.e_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_ehdr.e_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_ehdr.e_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_ehdr.e_shnum); 242 243 if (gf->gf_ehdr.e_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_ehdr.e_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) * 261 gf->gf_ehdr.e_shnum, UM_SLEEP); 262 263 shp = shdrs; 264 gsp = gf->gf_sects; 265 266 for (i = 0; i < gf->gf_ehdr.e_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 (%hu entries)\n", 363 IOP_NAME(gf->gf_io), gf->gf_ehdr.e_phnum); 364 365 if (gf->gf_ehdr.e_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_ehdr.e_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) * 383 gf->gf_ehdr.e_phnum, UM_SLEEP); 384 385 php = phdrs; 386 gpp = gf->gf_phdrs; 387 388 /* 389 * Iterate through the list of phdrs locating those that are of type 390 * PT_LOAD; increment gf_npload so we know how many are loadable. 391 */ 392 for (i = 0; i < gf->gf_ehdr.e_phnum; i++, php += phdr_size, gpp++) { 393 (void) elf2gelf(php, gpp); 394 if (gpp->p_type != PT_LOAD) 395 continue; 396 397 mdb_dprintf(MDB_DBG_ELF, "PT_LOAD va=0x%llx flags=0x%x " 398 "memsz=%llu filesz=%llu off=%llu\n", (u_longlong_t) 399 gpp->p_vaddr, gpp->p_flags, (u_longlong_t)gpp->p_memsz, 400 (u_longlong_t)gpp->p_filesz, (u_longlong_t)gpp->p_offset); 401 402 gf->gf_npload++; 403 } 404 405 /* 406 * Now we sort the phdrs array using a comparison routine which 407 * arranges for the PT_LOAD phdrs with non-zero virtual addresses 408 * to come first sorted by virtual address. This means that we 409 * can access the complete phdr table by examining the array 410 * gf->gf_phdrs[0 .. gf->gf_ehdr.e_phnum - 1], and we can access a 411 * sorted array of valid PT_LOAD pdhrs by examining the array 412 * gf->gf_phdrs[0 .. gf->gf_npload - 1]. 413 */ 414 qsort(gf->gf_phdrs, gf->gf_ehdr.e_phnum, sizeof (GElf_Phdr), 415 gelf_phdr_compare); 416 417 /* 418 * Locate the PT_DYNAMIC Phdr if one is present; we save this 419 * Phdr pointer in gf->gf_dynp for future use. 420 */ 421 for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_ehdr.e_phnum; i++, gpp++) { 422 if (gpp->p_type == PT_DYNAMIC) { 423 mdb_dprintf(MDB_DBG_ELF, "PT_DYNAMIC " 424 "filesize = %lluULL off=%lluULL\n", 425 (u_longlong_t)gpp->p_filesz, 426 (u_longlong_t)gpp->p_offset); 427 428 gf->gf_dynp = gpp; 429 break; 430 } 431 } 432 433 mdb_free(phdrs, nbytes); 434 return (gf); 435 } 436 437 static GElf_Dyn * 438 gelf32_to_dyn(const Elf32_Dyn *src, GElf_Dyn *dst) 439 { 440 if (src != NULL) { 441 dst->d_tag = (GElf_Xword)(Elf32_Word)src->d_tag; 442 dst->d_un.d_ptr = src->d_un.d_ptr; 443 return (dst); 444 } 445 446 return (NULL); 447 } 448 449 static GElf_Dyn * 450 gelf64_to_dyn(const Elf64_Dyn *src, GElf_Dyn *dst) 451 { 452 if (src != NULL) { 453 bcopy(src, dst, sizeof (Elf64_Dyn)); 454 return (dst); 455 } 456 457 return (NULL); 458 } 459 460 static GElf_Xword 461 gelf_dyn_lookup(mdb_gelf_file_t *gf, GElf_Xword tag) 462 { 463 size_t i; 464 465 for (i = 0; i < gf->gf_ndyns; i++) { 466 if (gf->gf_dyns[i].d_tag == tag) 467 return (gf->gf_dyns[i].d_un.d_val); 468 } 469 470 return ((GElf_Xword)-1L); 471 } 472 473 static GElf_Dyn * 474 gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size, 475 GElf_Dyn *(*elf2gelf)(const void *, GElf_Dyn *)) 476 { 477 size_t nbytes, ndyns, i; 478 caddr_t dyns, dp; 479 GElf_Dyn *gdp; 480 481 off64_t dyn_addr; 482 483 if (gf->gf_dyns != NULL) 484 return (gf->gf_dyns); /* Already loaded */ 485 486 if (gf->gf_dynp == NULL) 487 return (NULL); /* No PT_DYNAMIC entry was found */ 488 489 nbytes = gf->gf_dynp->p_filesz; 490 ndyns = nbytes / dyn_size; 491 492 /* 493 * If this is an executable in PROGRAM view, then p_vaddr is an 494 * absolute address; we need to subtract the virtual base address of 495 * the mapping. In FILE view, dyn_addr is just the file offset. 496 */ 497 if (gf->gf_mode == GF_PROGRAM) { 498 if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0) 499 dyn_addr = gf->gf_dynp->p_vaddr - gf->gf_phdrs->p_vaddr; 500 else 501 dyn_addr = gf->gf_dynp->p_vaddr; 502 } else { 503 mdb_gelf_sect_t *gsp = gf->gf_sects; 504 505 for (i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { 506 if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) { 507 dyn_addr = gsp->gs_shdr.sh_offset; 508 break; 509 } 510 } 511 512 if (i == gf->gf_ehdr.e_shnum) 513 return (NULL); /* No SHT_DYNAMIC entry was found */ 514 } 515 516 mdb_dprintf(MDB_DBG_ELF, "loading _DYNAMIC[] (%lu entries) " 517 "from offset %llx\n", (ulong_t)ndyns, (longlong_t)dyn_addr); 518 519 if (IOP_SEEK(gf->gf_io, dyn_addr, SEEK_SET) == -1) { 520 warn("failed to seek %s to _DYNAMIC", IOP_NAME(gf->gf_io)); 521 return (NULL); 522 } 523 524 dyns = mdb_alloc(nbytes, UM_SLEEP); 525 526 if (IOP_READ(gf->gf_io, dyns, nbytes) != nbytes) { 527 warn("failed to read %s:_DYNAMIC", IOP_NAME(gf->gf_io)); 528 mdb_free(dyns, nbytes); 529 return (NULL); 530 } 531 532 gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP); 533 gf->gf_ndyns = ndyns; 534 535 dp = dyns; 536 gdp = gf->gf_dyns; 537 538 for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) 539 (void) elf2gelf(dp, gdp); 540 541 mdb_free(dyns, nbytes); 542 return (gf->gf_dyns); 543 } 544 545 static mdb_gelf_file_t * 546 gelf32_init(mdb_gelf_file_t *gf, const Elf32_Ehdr *ehdr) 547 { 548 /* 549 * Convert the Elf32_Ehdr to a GElf_Ehdr 550 */ 551 bcopy(ehdr->e_ident, gf->gf_ehdr.e_ident, EI_NIDENT); 552 553 gf->gf_ehdr.e_type = ehdr->e_type; 554 gf->gf_ehdr.e_machine = ehdr->e_machine; 555 gf->gf_ehdr.e_version = ehdr->e_version; 556 gf->gf_ehdr.e_entry = ehdr->e_entry; 557 gf->gf_ehdr.e_phoff = ehdr->e_phoff; 558 gf->gf_ehdr.e_shoff = ehdr->e_shoff; 559 gf->gf_ehdr.e_flags = ehdr->e_flags; 560 gf->gf_ehdr.e_ehsize = ehdr->e_ehsize; 561 gf->gf_ehdr.e_phentsize = ehdr->e_phentsize; 562 gf->gf_ehdr.e_phnum = ehdr->e_phnum; 563 gf->gf_ehdr.e_shentsize = ehdr->e_shentsize; 564 gf->gf_ehdr.e_shnum = ehdr->e_shnum; 565 gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx; 566 567 /* 568 * Initialize the section and program headers. We skip initializing 569 * the section headers if this is a program image because they are 570 * not loadable and thus we can't get at them. 571 */ 572 if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf32_Shdr), 573 (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf32_to_shdr) == NULL) 574 return (NULL); 575 576 if (gelf_phdrs_init(gf, sizeof (Elf32_Phdr), 577 (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf32_to_phdr) == NULL) 578 return (NULL); 579 580 (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn), 581 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn); 582 583 return (gf); 584 } 585 586 static mdb_gelf_file_t * 587 gelf64_init(mdb_gelf_file_t *gf, Elf64_Ehdr *ehdr) 588 { 589 /* 590 * Save a copy of the ELF file header 591 */ 592 bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr)); 593 594 /* 595 * Initialize the section and program headers. We skip initializing 596 * the section headers if this is a program image because they are 597 * not loadable and thus we can't get at them. 598 */ 599 if (gf->gf_mode == GF_FILE && gelf_shdrs_init(gf, sizeof (Elf64_Shdr), 600 (GElf_Shdr *(*)(const void *, GElf_Shdr *))gelf64_to_shdr) == NULL) 601 return (NULL); 602 603 if (gelf_phdrs_init(gf, sizeof (Elf64_Phdr), 604 (GElf_Phdr *(*)(const void *, GElf_Phdr *))gelf64_to_phdr) == NULL) 605 return (NULL); 606 607 (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn), 608 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn); 609 610 return (gf); 611 } 612 613 int 614 mdb_gelf_check(mdb_io_t *io, Elf32_Ehdr *ehp, GElf_Half etype) 615 { 616 #ifdef _BIG_ENDIAN 617 uchar_t order = ELFDATA2MSB; 618 #else 619 uchar_t order = ELFDATA2LSB; 620 #endif 621 ssize_t nbytes; 622 623 (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); 624 nbytes = IOP_READ(io, ehp, sizeof (Elf32_Ehdr)); 625 626 if (nbytes == -1) { 627 if (etype != ET_NONE) 628 warn("failed to read ELF header from %s", IOP_NAME(io)); 629 return (-1); 630 } 631 632 if (nbytes != sizeof (Elf32_Ehdr) || 633 bcmp(&ehp->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) { 634 if (etype != ET_NONE) 635 warn("%s is not an ELF file\n", IOP_NAME(io)); 636 return (-1); 637 } 638 639 if (ehp->e_ident[EI_DATA] != order) { 640 warn("ELF file %s has different endianness from debugger\n", 641 IOP_NAME(io)); 642 return (-1); 643 } 644 645 if (ehp->e_version != EV_CURRENT) { 646 warn("ELF file %s uses different ELF version (%lu) than " 647 "debugger (%u)\n", IOP_NAME(io), 648 (ulong_t)ehp->e_version, EV_CURRENT); 649 return (-1); 650 } 651 652 if (etype != ET_NONE && ehp->e_type != etype) { 653 warn("ELF file %s is not of the expected type\n", IOP_NAME(io)); 654 return (-1); 655 } 656 657 return (0); 658 } 659 660 mdb_gelf_file_t * 661 mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode) 662 { 663 union { 664 Elf32_Ehdr h32; 665 Elf64_Ehdr h64; 666 } ehdr; 667 668 mdb_gelf_file_t *gf = mdb_zalloc(sizeof (mdb_gelf_file_t), UM_SLEEP); 669 670 ASSERT(mode == GF_FILE || mode == GF_PROGRAM); 671 gf->gf_mode = mode; 672 673 /* 674 * Assign the i/o backend now, but don't hold it until we're sure 675 * we're going to succeed; otherwise the caller will be responsible 676 * for mdb_io_destroy()ing it. 677 */ 678 gf->gf_io = io; 679 680 if (mdb_gelf_check(io, &ehdr.h32, etype) == -1) 681 goto err; 682 683 switch (ehdr.h32.e_ident[EI_CLASS]) { 684 case ELFCLASS32: 685 gf = gelf32_init(gf, &ehdr.h32); 686 break; 687 688 case ELFCLASS64: 689 if (IOP_SEEK(io, (off64_t)0L, SEEK_SET) == -1) { 690 warn("failed to seek %s", IOP_NAME(io)); 691 goto err; 692 } 693 694 if (IOP_READ(io, &ehdr.h64, sizeof (ehdr.h64)) != 695 sizeof (ehdr.h64)) { 696 warn("failed to read ELF header from %s", IOP_NAME(io)); 697 goto err; 698 } 699 700 gf = gelf64_init(gf, &ehdr.h64); 701 break; 702 703 default: 704 warn("%s is an unsupported ELF class: %u\n", 705 IOP_NAME(io), ehdr.h32.e_ident[EI_CLASS]); 706 goto err; 707 } 708 709 if (gf != NULL && gelf_sect_init(gf) != NULL) { 710 gf->gf_io = mdb_io_hold(io); 711 return (gf); 712 } 713 714 err: 715 if (gf != NULL) { 716 if (gf->gf_sects != NULL) { 717 mdb_free(gf->gf_sects, gf->gf_ehdr.e_shnum * 718 sizeof (mdb_gelf_sect_t)); 719 } 720 mdb_free(gf, sizeof (mdb_gelf_file_t)); 721 } 722 return (NULL); 723 } 724 725 void 726 mdb_gelf_destroy(mdb_gelf_file_t *gf) 727 { 728 mdb_gelf_sect_t *gsp; 729 GElf_Half i; 730 731 for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { 732 if (gsp->gs_data != NULL) 733 mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size); 734 } 735 736 mdb_free(gf->gf_sects, 737 gf->gf_ehdr.e_shnum * sizeof (mdb_gelf_sect_t)); 738 739 mdb_free(gf->gf_phdrs, 740 gf->gf_ehdr.e_phnum * sizeof (GElf_Phdr)); 741 742 mdb_io_rele(gf->gf_io); 743 mdb_free(gf, sizeof (mdb_gelf_file_t)); 744 } 745 746 /* 747 * Sort comparison function for 32-bit symbol address-to-name lookups. We sort 748 * symbols by value. If values are equal, we prefer the symbol that is 749 * non-zero sized, typed, not weak, or lexically first, in that order. 750 */ 751 static int 752 gelf32_sym_compare(const void *lp, const void *rp) 753 { 754 Elf32_Sym *lhs = *((Elf32_Sym **)lp); 755 Elf32_Sym *rhs = *((Elf32_Sym **)rp); 756 757 if (lhs->st_value != rhs->st_value) 758 return (lhs->st_value > rhs->st_value ? 1 : -1); 759 760 if ((lhs->st_size == 0) != (rhs->st_size == 0)) 761 return (lhs->st_size == 0 ? 1 : -1); 762 763 if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 764 (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 765 return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 766 767 if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != 768 (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) 769 return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 770 771 return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name)); 772 } 773 774 /* 775 * Sort comparison function for 64-bit symbol address-to-name lookups. We sort 776 * symbols by value. If values are equal, we prefer the symbol that is 777 * non-zero sized, typed, not weak, or lexically first, in that order. 778 */ 779 static int 780 gelf64_sym_compare(const void *lp, const void *rp) 781 { 782 Elf64_Sym *lhs = *((Elf64_Sym **)lp); 783 Elf64_Sym *rhs = *((Elf64_Sym **)rp); 784 785 if (lhs->st_value != rhs->st_value) 786 return (lhs->st_value > rhs->st_value ? 1 : -1); 787 788 if ((lhs->st_size == 0) != (rhs->st_size == 0)) 789 return (lhs->st_size == 0 ? 1 : -1); 790 791 if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 792 (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 793 return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 794 795 if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != 796 (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) 797 return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 798 799 return (strcmp(gelf_strtab + lhs->st_name, gelf_strtab + rhs->st_name)); 800 } 801 802 static void 803 gelf32_symtab_sort(mdb_gelf_symtab_t *gst) 804 { 805 Elf32_Sym **sympp = (Elf32_Sym **)gst->gst_asmap; 806 mdb_var_t *v; 807 808 mdb_nv_rewind(&gst->gst_nv); 809 810 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 811 Elf32_Sym *sym = MDB_NV_COOKIE(v); 812 if (sym->st_value != 0 && 813 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 814 *sympp++ = sym; 815 } 816 817 gst->gst_aslen = (size_t)(sympp - (Elf32_Sym **)gst->gst_asmap); 818 ASSERT(gst->gst_aslen <= gst->gst_asrsv); 819 820 gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL; 821 822 qsort(gst->gst_asmap, gst->gst_aslen, 823 sizeof (Elf32_Sym *), gelf32_sym_compare); 824 825 gelf_strtab = NULL; 826 } 827 828 static void 829 gelf32_symtab_init(mdb_gelf_symtab_t *gst) 830 { 831 const char *base = (const char *)gst->gst_ssect->gs_data; 832 Elf32_Sym *sym = gst->gst_dsect->gs_data; 833 mdb_nv_t *nv = &gst->gst_nv; 834 835 Elf32_Word ss_size = gst->gst_ssect->gs_shdr.sh_size; 836 size_t asrsv = 0; 837 GElf_Word i, n; 838 839 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf32_Sym)) { 840 warn("%s sh_entsize %llu != sizeof (Elf32_Sym); " 841 "using %u instead\n", gst->gst_dsect->gs_name, 842 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 843 (uint_t)sizeof (Elf32_Sym)); 844 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf32_Sym); 845 } 846 847 n = gst->gst_dsect->gs_shdr.sh_size / 848 gst->gst_dsect->gs_shdr.sh_entsize; 849 850 for (i = 0; i < n; i++, sym++) { 851 const char *name = base + sym->st_name; 852 uchar_t type = ELF32_ST_TYPE(sym->st_info); 853 854 if (type >= STT_NUM || type == STT_SECTION) 855 continue; /* skip sections and unknown types */ 856 857 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 858 if (sym->st_name >= ss_size || name[0] != '\0') { 859 warn("ignoring %s symbol [%u]: invalid name\n", 860 gst->gst_dsect->gs_name, i); 861 sym->st_name = 0; 862 } 863 continue; /* skip corrupt or empty names */ 864 } 865 866 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 867 868 if (sym->st_value != 0 && 869 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 870 asrsv++; /* reserve space in the address map */ 871 } 872 873 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 874 GElf_Word smax = gst->gst_ehdr->e_shnum; 875 mdb_gelf_sect_t *gsp; 876 877 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 878 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 879 gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 880 sym->st_value += gsp->gs_shdr.sh_offset; 881 882 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || 883 sym->st_size != 0) 884 asrsv++; /* reserve space in asmap */ 885 } 886 } 887 } 888 889 gst->gst_asmap = mdb_alloc(sizeof (Elf32_Sym *) * asrsv, UM_SLEEP); 890 gst->gst_asrsv = asrsv; 891 892 gelf32_symtab_sort(gst); 893 } 894 895 static void 896 gelf64_symtab_sort(mdb_gelf_symtab_t *gst) 897 { 898 Elf64_Sym **sympp = (Elf64_Sym **)gst->gst_asmap; 899 mdb_var_t *v; 900 901 mdb_nv_rewind(&gst->gst_nv); 902 903 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 904 Elf64_Sym *sym = MDB_NV_COOKIE(v); 905 if (sym->st_value != 0 && 906 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 907 *sympp++ = sym; 908 } 909 910 gst->gst_aslen = (size_t)(sympp - (Elf64_Sym **)gst->gst_asmap); 911 ASSERT(gst->gst_aslen <= gst->gst_asrsv); 912 913 gelf_strtab = gst->gst_ssect ? gst->gst_ssect->gs_data : NULL; 914 915 qsort(gst->gst_asmap, gst->gst_aslen, 916 sizeof (Elf64_Sym *), gelf64_sym_compare); 917 918 gelf_strtab = NULL; 919 } 920 921 static void 922 gelf64_symtab_init(mdb_gelf_symtab_t *gst) 923 { 924 const char *base = (const char *)gst->gst_ssect->gs_data; 925 Elf64_Sym *sym = gst->gst_dsect->gs_data; 926 mdb_nv_t *nv = &gst->gst_nv; 927 928 Elf64_Xword ss_size = gst->gst_ssect->gs_shdr.sh_size; 929 size_t asrsv = 0; 930 GElf_Word i, n; 931 932 if (gst->gst_dsect->gs_shdr.sh_entsize != sizeof (Elf64_Sym)) { 933 warn("%s sh_entsize %llu != sizeof (Elf64_Sym); " 934 "using %u instead\n", gst->gst_dsect->gs_name, 935 (u_longlong_t)gst->gst_dsect->gs_shdr.sh_entsize, 936 (uint_t)sizeof (Elf64_Sym)); 937 gst->gst_dsect->gs_shdr.sh_entsize = sizeof (Elf64_Sym); 938 } 939 940 n = gst->gst_dsect->gs_shdr.sh_size / 941 gst->gst_dsect->gs_shdr.sh_entsize; 942 943 for (i = 0; i < n; i++, sym++) { 944 const char *name = base + sym->st_name; 945 uchar_t type = ELF64_ST_TYPE(sym->st_info); 946 947 if (type >= STT_NUM || type == STT_SECTION) 948 continue; /* skip sections and unknown types */ 949 950 if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { 951 if (sym->st_name >= ss_size || name[0] != '\0') { 952 warn("ignoring %s symbol [%u]: invalid name\n", 953 gst->gst_dsect->gs_name, i); 954 sym->st_name = 0; 955 } 956 continue; /* skip corrupt or empty names */ 957 } 958 959 (void) mdb_nv_insert(nv, name, NULL, (uintptr_t)sym, GST_NVFLG); 960 961 if (sym->st_value != 0 && 962 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 963 asrsv++; /* reserve space in the address map */ 964 } 965 966 if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { 967 GElf_Word smax = gst->gst_ehdr->e_shnum; 968 mdb_gelf_sect_t *gsp; 969 970 for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { 971 if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < smax) { 972 gsp = &gst->gst_file->gf_sects[sym->st_shndx]; 973 sym->st_value += gsp->gs_shdr.sh_offset; 974 975 if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || 976 sym->st_size != 0) 977 asrsv++; /* reserve space in asmap */ 978 } 979 } 980 } 981 982 gst->gst_asmap = mdb_alloc(sizeof (Elf64_Sym *) * asrsv, UM_SLEEP); 983 gst->gst_asrsv = asrsv; 984 985 gelf64_symtab_sort(gst); 986 } 987 988 mdb_gelf_symtab_t * 989 mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype, 990 uint_t tabid) 991 { 992 mdb_gelf_sect_t *gsp; 993 const char *dsname = NULL; 994 const char *ssname; 995 GElf_Half i; 996 GElf_Word link; 997 998 /* 999 * Examine the sh_link field in the the Elf header to get the name 1000 * of the corresponding strings section 1001 */ 1002 for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { 1003 if (gsp->gs_shdr.sh_type == elftype) { 1004 dsname = gsp->gs_name; 1005 link = gsp->gs_shdr.sh_link; 1006 break; 1007 } 1008 } 1009 1010 if (dsname == NULL) 1011 return (NULL); 1012 1013 if (link > gf->gf_ehdr.e_shnum) { 1014 /* 1015 * Invalid link number due to corrupt elf file. 1016 */ 1017 warn("link number %ud larger than number of sections %d\n", 1018 link, gf->gf_ehdr.e_shnum); 1019 return (NULL); 1020 } 1021 1022 ssname = (gf->gf_sects + link)->gs_name; 1023 1024 return (mdb_gelf_symtab_create_file_by_name(gf, dsname, ssname, tabid)); 1025 } 1026 1027 mdb_gelf_symtab_t * 1028 mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf, 1029 const char *dsname, const char *ssname, uint_t tabid) 1030 { 1031 mdb_gelf_symtab_t *gst; 1032 mdb_gelf_sect_t *gsp; 1033 GElf_Half i; 1034 1035 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1036 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1037 1038 gst->gst_asmap = NULL; 1039 gst->gst_aslen = 0; 1040 gst->gst_asrsv = 0; 1041 gst->gst_ehdr = &gf->gf_ehdr; 1042 gst->gst_file = gf; 1043 gst->gst_dsect = NULL; 1044 gst->gst_ssect = NULL; 1045 gst->gst_id = 0; 1046 gst->gst_tabid = tabid; 1047 1048 for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { 1049 if (strcmp(gsp->gs_name, dsname) == 0) { 1050 gst->gst_dsect = gsp; 1051 break; 1052 } 1053 } 1054 1055 for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { 1056 if (strcmp(gsp->gs_name, ssname) == 0) { 1057 gst->gst_ssect = gsp; 1058 break; 1059 } 1060 } 1061 1062 if (gst->gst_dsect == NULL || gst->gst_ssect == NULL) 1063 goto err; /* Failed to locate data or string section */ 1064 1065 if (gelf_sect_load(gf, gst->gst_dsect) == NULL) 1066 goto err; /* Failed to load data section */ 1067 1068 if (gelf_sect_load(gf, gst->gst_ssect) == NULL) 1069 goto err; /* Failed to load string section */ 1070 1071 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 1072 gelf32_symtab_init(gst); 1073 else 1074 gelf64_symtab_init(gst); 1075 1076 return (gst); 1077 1078 err: 1079 mdb_nv_destroy(&gst->gst_nv); 1080 mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 1081 return (NULL); 1082 } 1083 1084 mdb_gelf_symtab_t * 1085 mdb_gelf_symtab_create_raw(const GElf_Ehdr *ehdr, const void *dshdr, 1086 void *ddata, const void *sshdr, void *sdata, uint_t tabid) 1087 { 1088 mdb_gelf_symtab_t *gst; 1089 1090 gst = mdb_alloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1091 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1092 1093 gst->gst_asmap = NULL; 1094 gst->gst_aslen = 0; 1095 gst->gst_asrsv = 0; 1096 gst->gst_ehdr = ehdr; 1097 gst->gst_file = NULL; /* Flag for raw symtab */ 1098 gst->gst_id = 0; 1099 gst->gst_tabid = tabid; 1100 1101 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1102 gst->gst_dsect->gs_name = ".symtab"; 1103 gst->gst_dsect->gs_data = ddata; 1104 1105 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1106 gst->gst_ssect->gs_name = ".strtab"; 1107 gst->gst_ssect->gs_data = sdata; 1108 1109 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1110 (void) gelf32_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 1111 (void) gelf32_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 1112 gelf32_symtab_init(gst); 1113 } else { 1114 (void) gelf64_to_shdr(dshdr, &gst->gst_dsect->gs_shdr); 1115 (void) gelf64_to_shdr(sshdr, &gst->gst_ssect->gs_shdr); 1116 gelf64_symtab_init(gst); 1117 } 1118 1119 return (gst); 1120 } 1121 1122 mdb_gelf_symtab_t * 1123 mdb_gelf_symtab_create_dynamic(mdb_gelf_file_t *gf, uint_t tabid) 1124 { 1125 GElf_Addr dt_symtab, dt_strtab, dt_hash; 1126 GElf_Xword dt_syment, dt_strsz; 1127 1128 mdb_gelf_symtab_t *gst; 1129 uint_t hash_h[2]; 1130 off64_t base = 0; 1131 1132 ASSERT(gf->gf_mode == GF_PROGRAM); 1133 1134 /* 1135 * Read in and cache the array of GElf_Dyn structures from the 1136 * PT_DYNAMIC phdr. Abort if this is not possible. 1137 */ 1138 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1139 (void) gelf_dyns_init(gf, sizeof (Elf32_Dyn), 1140 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf32_to_dyn); 1141 } else { 1142 (void) gelf_dyns_init(gf, sizeof (Elf64_Dyn), 1143 (GElf_Dyn *(*)(const void *, GElf_Dyn *))gelf64_to_dyn); 1144 } 1145 1146 /* 1147 * Pre-fetch all the DT_* entries we will need for creating the 1148 * dynamic symbol table; abort if any are missing. 1149 */ 1150 if ((dt_hash = gelf_dyn_lookup(gf, DT_HASH)) == -1L) { 1151 warn("failed to get DT_HASH for %s\n", IOP_NAME(gf->gf_io)); 1152 return (NULL); 1153 } 1154 1155 if ((dt_symtab = gelf_dyn_lookup(gf, DT_SYMTAB)) == -1L) { 1156 warn("failed to get DT_SYMTAB for %s\n", IOP_NAME(gf->gf_io)); 1157 return (NULL); 1158 } 1159 1160 if ((dt_syment = gelf_dyn_lookup(gf, DT_SYMENT)) == -1L) { 1161 warn("failed to get DT_SYMENT for %s\n", IOP_NAME(gf->gf_io)); 1162 return (NULL); 1163 } 1164 1165 if ((dt_strtab = gelf_dyn_lookup(gf, DT_STRTAB)) == -1L) { 1166 warn("failed to get DT_STRTAB for %s\n", IOP_NAME(gf->gf_io)); 1167 return (NULL); 1168 } 1169 1170 if ((dt_strsz = gelf_dyn_lookup(gf, DT_STRSZ)) == -1L) { 1171 warn("failed to get DT_STRSZ for %s\n", IOP_NAME(gf->gf_io)); 1172 return (NULL); 1173 } 1174 1175 /* 1176 * If this is an executable, then DT_HASH is an absolute address; 1177 * we need to subtract the virtual base address of the mapping. 1178 */ 1179 if (gf->gf_ehdr.e_type == ET_EXEC && gf->gf_npload != 0) 1180 base = (off64_t)gf->gf_phdrs->p_vaddr; 1181 1182 /* 1183 * Read in the header for the DT_HASH: this consists of nbucket 1184 * and nchain values (nchain is the number of hashed symbols). 1185 */ 1186 if (IOP_SEEK(gf->gf_io, (off64_t)dt_hash - base, SEEK_SET) == -1) { 1187 warn("failed to seek ELF file to start of DT_HASH"); 1188 return (NULL); 1189 } 1190 1191 if (IOP_READ(gf->gf_io, hash_h, sizeof (hash_h)) != sizeof (hash_h)) { 1192 warn("failed to read DT_HASH header"); 1193 return (NULL); 1194 } 1195 1196 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1197 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1198 1199 gst->gst_asmap = NULL; 1200 gst->gst_aslen = 0; 1201 gst->gst_asrsv = 0; 1202 gst->gst_ehdr = &gf->gf_ehdr; 1203 gst->gst_file = gf; 1204 gst->gst_id = 0; 1205 gst->gst_tabid = tabid; 1206 1207 gst->gst_dsect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1208 gst->gst_dsect->gs_name = ".dynsym"; 1209 gst->gst_dsect->gs_shdr.sh_offset = dt_symtab - (GElf_Addr)base; 1210 gst->gst_dsect->gs_shdr.sh_size = hash_h[1] * dt_syment; 1211 gst->gst_dsect->gs_shdr.sh_entsize = dt_syment; 1212 1213 gst->gst_ssect = mdb_zalloc(sizeof (mdb_gelf_sect_t), UM_SLEEP); 1214 gst->gst_ssect->gs_name = ".dynstr"; 1215 gst->gst_ssect->gs_shdr.sh_offset = dt_strtab - (GElf_Addr)base; 1216 gst->gst_ssect->gs_shdr.sh_size = dt_strsz; 1217 gst->gst_ssect->gs_shdr.sh_entsize = 0; 1218 1219 if (gelf_sect_load(gf, gst->gst_dsect) == NULL) 1220 goto err; 1221 1222 if (gelf_sect_load(gf, gst->gst_ssect) == NULL) 1223 goto err; 1224 1225 if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) 1226 gelf32_symtab_init(gst); 1227 else 1228 gelf64_symtab_init(gst); 1229 1230 return (gst); 1231 1232 err: 1233 mdb_gelf_symtab_destroy(gst); 1234 return (NULL); 1235 } 1236 1237 mdb_gelf_symtab_t * 1238 mdb_gelf_symtab_create_mutable(void) 1239 { 1240 mdb_gelf_symtab_t *gst; 1241 static GElf_Ehdr ehdr; 1242 1243 gst = mdb_zalloc(sizeof (mdb_gelf_symtab_t), UM_SLEEP); 1244 (void) mdb_nv_create(&gst->gst_nv, UM_SLEEP); 1245 gst->gst_ehdr = &ehdr; 1246 1247 if (ehdr.e_version == 0) { 1248 #ifdef _LP64 1249 uchar_t class = ELFCLASS64; 1250 #else 1251 uchar_t class = ELFCLASS32; 1252 #endif 1253 1254 #ifdef _BIG_ENDIAN 1255 uchar_t data = ELFDATA2MSB; 1256 #else 1257 uchar_t data = ELFDATA2LSB; 1258 #endif 1259 /* 1260 * Since all mutable symbol tables will use a native Ehdr, 1261 * we can just have a single static copy which they all 1262 * point to and we only need initialize once. 1263 */ 1264 ehdr.e_ident[EI_MAG0] = ELFMAG0; 1265 ehdr.e_ident[EI_MAG1] = ELFMAG1; 1266 ehdr.e_ident[EI_MAG2] = ELFMAG2; 1267 ehdr.e_ident[EI_MAG3] = ELFMAG3; 1268 ehdr.e_ident[EI_CLASS] = class; 1269 ehdr.e_ident[EI_DATA] = data; 1270 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 1271 ehdr.e_type = ET_NONE; 1272 ehdr.e_version = EV_CURRENT; 1273 } 1274 1275 return (gst); 1276 } 1277 1278 void 1279 mdb_gelf_symtab_destroy(mdb_gelf_symtab_t *gst) 1280 { 1281 if (gst->gst_file == NULL) { 1282 if (gst->gst_dsect == NULL && gst->gst_ssect == NULL) { 1283 mdb_var_t *v; 1284 1285 mdb_nv_rewind(&gst->gst_nv); 1286 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 1287 char *name = (char *)mdb_nv_get_name(v); 1288 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1289 1290 mdb_free(name, strlen(name) + 1); 1291 mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 1292 } 1293 1294 } else { 1295 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 1296 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 1297 } 1298 1299 } else if (gst->gst_file->gf_mode == GF_PROGRAM) { 1300 mdb_gelf_sect_t *dsect = gst->gst_dsect; 1301 mdb_gelf_sect_t *ssect = gst->gst_ssect; 1302 1303 if (dsect->gs_data != NULL) 1304 mdb_free(dsect->gs_data, dsect->gs_shdr.sh_size); 1305 if (ssect->gs_data != NULL) 1306 mdb_free(ssect->gs_data, ssect->gs_shdr.sh_size); 1307 1308 mdb_free(gst->gst_dsect, sizeof (mdb_gelf_sect_t)); 1309 mdb_free(gst->gst_ssect, sizeof (mdb_gelf_sect_t)); 1310 } 1311 1312 mdb_nv_destroy(&gst->gst_nv); 1313 mdb_free(gst->gst_asmap, gst->gst_asrsv * sizeof (void *)); 1314 mdb_free(gst, sizeof (mdb_gelf_symtab_t)); 1315 } 1316 1317 size_t 1318 mdb_gelf_symtab_size(mdb_gelf_symtab_t *gst) 1319 { 1320 return (mdb_nv_size(&gst->gst_nv)); 1321 } 1322 1323 static GElf_Sym * 1324 gelf32_to_sym(const Elf32_Sym *src, GElf_Sym *dst) 1325 { 1326 if (src != NULL) { 1327 dst->st_name = src->st_name; 1328 dst->st_info = src->st_info; 1329 dst->st_other = src->st_other; 1330 dst->st_shndx = src->st_shndx; 1331 dst->st_value = src->st_value; 1332 dst->st_size = src->st_size; 1333 return (dst); 1334 } 1335 1336 return (NULL); 1337 } 1338 1339 static GElf_Sym * 1340 gelf64_to_sym(const Elf64_Sym *src, GElf_Sym *dst) 1341 { 1342 if (src != NULL) { 1343 bcopy(src, dst, sizeof (GElf_Sym)); 1344 return (dst); 1345 } 1346 1347 return (NULL); 1348 } 1349 1350 /*ARGSUSED*/ 1351 static GElf_Sym * 1352 gelf64_nocopy(const Elf64_Sym *src, GElf_Sym *dst) 1353 { 1354 return ((GElf_Sym *)src); 1355 } 1356 1357 static const void * 1358 gelf32_sym_search(const Elf32_Sym **asmap, size_t aslen, uintptr_t addr) 1359 { 1360 ulong_t i, mid, lo = 0, hi = aslen - 1; 1361 const Elf32_Sym *symp; 1362 Elf32_Addr v; 1363 size_t size; 1364 1365 if (aslen == 0) 1366 return (NULL); 1367 1368 while (hi - lo > 1) { 1369 mid = (lo + hi) / 2; 1370 if (addr >= asmap[mid]->st_value) 1371 lo = mid; 1372 else 1373 hi = mid; 1374 } 1375 1376 i = addr < asmap[hi]->st_value ? lo : hi; 1377 symp = asmap[i]; 1378 v = symp->st_value; 1379 1380 /* 1381 * If the previous entry has the same value, improve our choice. The 1382 * order of equal-valued symbols is determined by gelf32_sym_compare(). 1383 */ 1384 while (i-- != 0 && asmap[i]->st_value == v) 1385 symp = asmap[i]; 1386 1387 /* 1388 * If an absolute symbol distance was specified, use that; otherwise 1389 * use the ELF symbol size, or 1 byte if the ELF size is zero. 1390 */ 1391 if (mdb.m_symdist == 0) 1392 size = MAX(symp->st_size, 1); 1393 else 1394 size = mdb.m_symdist; 1395 1396 if (addr - symp->st_value < size) 1397 return (symp); 1398 1399 return (NULL); 1400 } 1401 1402 static const void * 1403 gelf64_sym_search(const Elf64_Sym **asmap, size_t aslen, uintptr_t addr) 1404 { 1405 ulong_t i, mid, lo = 0, hi = aslen - 1; 1406 const Elf64_Sym *symp; 1407 Elf64_Addr v; 1408 size_t size; 1409 1410 if (aslen == 0) 1411 return (NULL); 1412 1413 while (hi - lo > 1) { 1414 mid = (lo + hi) / 2; 1415 if (addr >= asmap[mid]->st_value) 1416 lo = mid; 1417 else 1418 hi = mid; 1419 } 1420 1421 i = addr < asmap[hi]->st_value ? lo : hi; 1422 symp = asmap[i]; 1423 v = symp->st_value; 1424 1425 /* 1426 * If the previous entry has the same value, improve our choice. The 1427 * order of equal-valued symbols is determined by gelf64_sym_compare(). 1428 */ 1429 while (i-- != 0 && asmap[i]->st_value == v) 1430 symp = asmap[i]; 1431 1432 /* 1433 * If an absolute symbol distance was specified, use that; otherwise 1434 * use the ELF symbol size, or 1 byte if the ELF size is zero. 1435 */ 1436 if (mdb.m_symdist == 0) 1437 size = MAX(symp->st_size, 1); 1438 else 1439 size = mdb.m_symdist; 1440 1441 if (addr - symp->st_value < size) 1442 return (symp); 1443 1444 return (NULL); 1445 } 1446 1447 const char * 1448 mdb_gelf_sym_name(mdb_gelf_symtab_t *gst, const GElf_Sym *sym) 1449 { 1450 const mdb_gelf_dsym_t *dsp; 1451 1452 if (gst->gst_ssect != NULL) 1453 return ((const char *)gst->gst_ssect->gs_data + sym->st_name); 1454 1455 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1456 dsp = gelf32_sym_search(gst->gst_asmap, 1457 gst->gst_aslen, sym->st_value); 1458 else 1459 dsp = gelf64_sym_search(gst->gst_asmap, 1460 gst->gst_aslen, sym->st_value); 1461 1462 if (dsp != NULL) 1463 return (mdb_nv_get_name(dsp->ds_var)); 1464 1465 return (NULL); 1466 } 1467 1468 int 1469 mdb_gelf_sym_closer(const GElf_Sym *s1, const GElf_Sym *s2, uintptr_t addr) 1470 { 1471 uintptr_t v1 = (uintptr_t)s1->st_value; 1472 uintptr_t v2 = (uintptr_t)s2->st_value; 1473 1474 uintptr_t d1 = v1 > addr ? v1 - addr : addr - v1; 1475 uintptr_t d2 = v2 > addr ? v2 - addr : addr - v2; 1476 1477 return (d1 < d2); 1478 } 1479 1480 int 1481 mdb_gelf_symtab_lookup_by_addr(mdb_gelf_symtab_t *gst, uintptr_t addr, 1482 uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym, uint_t *idp) 1483 { 1484 union { 1485 const mdb_gelf_dsym_t *dsp; 1486 const Elf32_Sym *s32; 1487 const Elf64_Sym *s64; 1488 caddr_t sp; 1489 } u; 1490 1491 const char *name; 1492 1493 if (gst == NULL) 1494 return (set_errno(EMDB_NOSYMADDR)); 1495 1496 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1497 u.s32 = gelf32_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 1498 if (gelf32_to_sym(u.s32, sym) == NULL) 1499 return (set_errno(EMDB_NOSYMADDR)); 1500 } else { 1501 u.s64 = gelf64_sym_search(gst->gst_asmap, gst->gst_aslen, addr); 1502 if (gelf64_to_sym(u.s64, sym) == NULL) 1503 return (set_errno(EMDB_NOSYMADDR)); 1504 } 1505 1506 if ((flags & GST_EXACT) && (sym->st_value != addr)) 1507 return (set_errno(EMDB_NOSYMADDR)); 1508 1509 if (gst->gst_ssect != NULL) { 1510 name = (const char *)gst->gst_ssect->gs_data + sym->st_name; 1511 if (idp != NULL) { 1512 *idp = (u.sp - (caddr_t)gst->gst_dsect->gs_data) / 1513 gst->gst_dsect->gs_shdr.sh_entsize; 1514 } 1515 } else { 1516 name = mdb_nv_get_name(u.dsp->ds_var); 1517 if (idp != NULL) 1518 *idp = u.dsp->ds_id; 1519 } 1520 1521 if (nbytes > 0) { 1522 (void) strncpy(buf, name, nbytes - 1); 1523 buf[nbytes - 1] = '\0'; 1524 } 1525 return (0); 1526 } 1527 1528 int 1529 mdb_gelf_symtab_lookup_by_name(mdb_gelf_symtab_t *gst, const char *name, 1530 GElf_Sym *sym, uint_t *idp) 1531 { 1532 mdb_var_t *v; 1533 1534 if (gst != NULL && (v = mdb_nv_lookup(&gst->gst_nv, name)) != NULL) { 1535 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1536 (void) gelf32_to_sym(mdb_nv_get_cookie(v), sym); 1537 else 1538 (void) gelf64_to_sym(mdb_nv_get_cookie(v), sym); 1539 1540 if (idp != NULL) { 1541 if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 1542 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1543 *idp = dsp->ds_id; 1544 } else { 1545 *idp = ((uintptr_t)mdb_nv_get_cookie(v) - 1546 (uintptr_t)gst->gst_dsect->gs_data) / 1547 gst->gst_dsect->gs_shdr.sh_entsize; 1548 } 1549 } 1550 1551 return (0); 1552 } 1553 1554 return (set_errno(EMDB_NOSYM)); 1555 } 1556 1557 int 1558 mdb_gelf_symtab_lookup_by_file(mdb_gelf_symtab_t *gst, const char *file, 1559 const char *name, GElf_Sym *sym, uint_t *idp) 1560 { 1561 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 1562 size_t sym_size; 1563 caddr_t sp, ep; 1564 mdb_var_t *v; 1565 1566 if (gst == NULL) 1567 return (set_errno(EMDB_NOSYM)); 1568 1569 if ((v = mdb_nv_lookup(&gst->gst_nv, file)) == NULL) 1570 return (set_errno(EMDB_NOOBJ)); 1571 1572 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1573 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 1574 sym_size = sizeof (Elf32_Sym); 1575 } else { 1576 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_to_sym; 1577 sym_size = sizeof (Elf64_Sym); 1578 } 1579 1580 (void) s2gelf(mdb_nv_get_cookie(v), sym); 1581 1582 if (GELF_ST_TYPE(sym->st_info) != STT_FILE) 1583 return (set_errno(EMDB_NOOBJ)); 1584 1585 ep = (caddr_t)gst->gst_dsect->gs_data + gst->gst_dsect->gs_shdr.sh_size; 1586 sp = (caddr_t)mdb_nv_get_cookie(v); 1587 1588 /* 1589 * We assume that symbol lookups scoped by source file name are only 1590 * relevant for userland debugging and are a relatively rare request, 1591 * and so we use a simple but inefficient linear search with copying. 1592 */ 1593 for (sp += sym_size; sp < ep; sp += sym_size) { 1594 (void) s2gelf(sp, sym); /* Convert native symbol to GElf */ 1595 1596 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION || 1597 GELF_ST_TYPE(sym->st_info) == STT_FILE || 1598 GELF_ST_BIND(sym->st_info) != STB_LOCAL) 1599 break; /* End of this file's locals */ 1600 1601 if (strcmp(mdb_gelf_sym_name(gst, sym), name) == 0) { 1602 if (idp != NULL) { 1603 *idp = (sp - (caddr_t) 1604 gst->gst_dsect->gs_data) / sym_size; 1605 } 1606 return (0); 1607 } 1608 } 1609 1610 return (set_errno(EMDB_NOSYM)); 1611 } 1612 1613 void 1614 mdb_gelf_symtab_iter(mdb_gelf_symtab_t *gst, int (*func)(void *, 1615 const GElf_Sym *, const char *, uint_t), void *private) 1616 { 1617 GElf_Sym *(*s2gelf)(const void *, GElf_Sym *); 1618 GElf_Sym sym, *symp; 1619 size_t sym_size; 1620 1621 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1622 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf32_to_sym; 1623 sym_size = sizeof (Elf32_Sym); 1624 } else { 1625 s2gelf = (GElf_Sym *(*)(const void *, GElf_Sym *))gelf64_nocopy; 1626 sym_size = sizeof (Elf64_Sym); 1627 } 1628 1629 /* 1630 * If this is a mutable symbol table, we iterate over the hash table 1631 * of symbol names; otherwise we go iterate over the data buffer. For 1632 * non-mutable tables, this means that ::nm will show all symbols, 1633 * including those with duplicate names (not present in gst_nv). 1634 */ 1635 if (gst->gst_file == NULL && gst->gst_dsect == NULL) { 1636 mdb_gelf_dsym_t *dsp; 1637 mdb_var_t *v; 1638 1639 mdb_nv_rewind(&gst->gst_nv); 1640 while ((v = mdb_nv_advance(&gst->gst_nv)) != NULL) { 1641 dsp = mdb_nv_get_cookie(v); 1642 symp = s2gelf(dsp, &sym); 1643 if (func(private, symp, mdb_nv_get_name(v), 1644 dsp->ds_id) == -1) 1645 break; 1646 } 1647 1648 } else { 1649 const char *sbase = gst->gst_ssect->gs_data; 1650 caddr_t sp = gst->gst_dsect->gs_data; 1651 caddr_t ep = sp + gst->gst_dsect->gs_shdr.sh_size; 1652 uint_t i; 1653 1654 for (i = 0; sp < ep; sp += sym_size, i++) { 1655 symp = s2gelf(sp, &sym); 1656 if (func(private, symp, sbase + symp->st_name, i) == -1) 1657 break; 1658 } 1659 } 1660 } 1661 1662 static void 1663 gelf_sym_to_32(const GElf_Sym *src, Elf32_Sym *dst) 1664 { 1665 dst->st_name = src->st_name; 1666 dst->st_info = src->st_info; 1667 dst->st_other = src->st_other; 1668 dst->st_shndx = src->st_shndx; 1669 dst->st_value = (Elf32_Addr)src->st_value; 1670 dst->st_size = (Elf32_Word)src->st_size; 1671 } 1672 1673 static void 1674 gelf_sym_to_64(const GElf_Sym *src, Elf64_Sym *dst) 1675 { 1676 bcopy(src, dst, sizeof (Elf64_Sym)); 1677 } 1678 1679 void 1680 mdb_gelf_symtab_insert(mdb_gelf_symtab_t *gst, 1681 const char *name, const GElf_Sym *symp) 1682 { 1683 mdb_gelf_dsym_t *dsp; 1684 mdb_var_t *v; 1685 1686 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 1687 v = mdb_nv_lookup(&gst->gst_nv, name); 1688 1689 if (v == NULL) { 1690 char *s = mdb_alloc(strlen(name) + 1, UM_SLEEP); 1691 (void) strcpy(s, name); 1692 1693 dsp = mdb_alloc(sizeof (mdb_gelf_dsym_t), UM_SLEEP); 1694 dsp->ds_id = gst->gst_id++; 1695 1696 dsp->ds_var = mdb_nv_insert(&gst->gst_nv, s, NULL, 1697 (uintptr_t)dsp, GST_NVFLG); 1698 1699 gst->gst_aslen++; 1700 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 1701 1702 if (gst->gst_aslen > gst->gst_asrsv) { 1703 mdb_free(gst->gst_asmap, 1704 sizeof (void *) * gst->gst_asrsv); 1705 1706 gst->gst_asrsv = gst->gst_asrsv != 0 ? 1707 gst->gst_asrsv * GST_GROW : GST_DEFSZ; 1708 1709 gst->gst_asmap = mdb_alloc(sizeof (void *) * 1710 gst->gst_asrsv, UM_SLEEP); 1711 } 1712 } else 1713 dsp = mdb_nv_get_cookie(v); 1714 1715 mdb_dprintf(MDB_DBG_ELF, "added symbol (\"%s\", %llx)\n", 1716 name, (u_longlong_t)symp->st_value); 1717 1718 bcopy(symp, &dsp->ds_sym, sizeof (GElf_Sym)); 1719 dsp->ds_sym.st_name = (uintptr_t)mdb_nv_get_name(dsp->ds_var); 1720 1721 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { 1722 gelf_sym_to_32(symp, &dsp->ds_u.ds_s32); 1723 gelf32_symtab_sort(gst); 1724 } else { 1725 gelf_sym_to_64(symp, &dsp->ds_u.ds_s64); 1726 gelf64_symtab_sort(gst); 1727 } 1728 } 1729 1730 void 1731 mdb_gelf_symtab_delete(mdb_gelf_symtab_t *gst, 1732 const char *name, GElf_Sym *symp) 1733 { 1734 mdb_var_t *v; 1735 1736 ASSERT(gst->gst_file == NULL && gst->gst_dsect == NULL); 1737 v = mdb_nv_lookup(&gst->gst_nv, name); 1738 1739 if (v != NULL) { 1740 char *name = (char *)mdb_nv_get_name(v); 1741 mdb_gelf_dsym_t *dsp = mdb_nv_get_cookie(v); 1742 1743 if (symp != NULL) 1744 bcopy(&dsp->ds_sym, symp, sizeof (GElf_Sym)); 1745 1746 mdb_dprintf(MDB_DBG_ELF, "removed symbol (\"%s\", %llx)\n", 1747 name, (u_longlong_t)dsp->ds_sym.st_value); 1748 1749 mdb_nv_remove(&gst->gst_nv, v); 1750 gst->gst_aslen--; 1751 ASSERT(gst->gst_aslen == mdb_nv_size(&gst->gst_nv)); 1752 1753 mdb_free(name, strlen(name) + 1); 1754 mdb_free(dsp, sizeof (mdb_gelf_dsym_t)); 1755 1756 if (gst->gst_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1757 gelf32_symtab_sort(gst); 1758 else 1759 gelf64_symtab_sort(gst); 1760 } 1761 } 1762 1763 static const GElf_Phdr * 1764 gelf_phdr_lookup(mdb_gelf_file_t *gf, uintptr_t addr) 1765 { 1766 const GElf_Phdr *gpp = gf->gf_phdrs; 1767 GElf_Half i; 1768 1769 for (i = 0; i < gf->gf_npload; i++, gpp++) { 1770 if (addr >= gpp->p_vaddr && addr < gpp->p_vaddr + gpp->p_memsz) 1771 return (gpp); 1772 } 1773 1774 return (NULL); 1775 } 1776 1777 ssize_t 1778 mdb_gelf_rw(mdb_gelf_file_t *gf, void *buf, size_t nbytes, uintptr_t addr, 1779 ssize_t (*prw)(mdb_io_t *, void *, size_t), mdb_gelf_rw_t rw) 1780 { 1781 ssize_t resid = nbytes; 1782 1783 while (resid != 0) { 1784 const GElf_Phdr *php = gelf_phdr_lookup(gf, addr); 1785 1786 uintptr_t mapoff; 1787 ssize_t memlen, filelen, len = 0; 1788 off64_t off; 1789 1790 if (php == NULL) 1791 break; /* No mapping for this address */ 1792 1793 mapoff = addr - php->p_vaddr; 1794 memlen = MIN(resid, php->p_memsz - mapoff); 1795 filelen = MIN(resid, php->p_filesz - mapoff); 1796 off = (off64_t)php->p_offset + mapoff; 1797 1798 if (filelen > 0 && (IOP_SEEK(gf->gf_io, off, SEEK_SET) != off || 1799 (len = prw(gf->gf_io, buf, filelen)) <= 0)) 1800 break; 1801 1802 if (rw == GIO_READ && len == filelen && filelen < memlen) { 1803 bzero((char *)buf + len, memlen - filelen); 1804 len += memlen - filelen; 1805 } 1806 1807 resid -= len; 1808 addr += len; 1809 buf = (char *)buf + len; 1810 } 1811 1812 if (resid == nbytes && nbytes != 0) 1813 return (set_errno(EMDB_NOMAP)); 1814 1815 return (nbytes - resid); 1816 } 1817