17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21c9a6ea2eSBryan Cantrill 227c478bd9Sstevel@tonic-gate /* 23c9a6ea2eSBryan Cantrill * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 25*a386cc11SRobert Mustacchi /* 26*a386cc11SRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27*a386cc11SRobert Mustacchi */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 317c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 327c478bd9Sstevel@tonic-gate #include <sys/kobj_impl.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/elf.h> 357c478bd9Sstevel@tonic-gate #include <sys/task.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <project.h> 397c478bd9Sstevel@tonic-gate #include <strings.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <libelf.h> 427c478bd9Sstevel@tonic-gate #include <limits.h> 437c478bd9Sstevel@tonic-gate #include <assert.h> 447c478bd9Sstevel@tonic-gate #include <errno.h> 457c478bd9Sstevel@tonic-gate #include <dirent.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <dt_strtab.h> 487c478bd9Sstevel@tonic-gate #include <dt_module.h> 497c478bd9Sstevel@tonic-gate #include <dt_impl.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static const char *dt_module_strtab; /* active strtab for qsort callbacks */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static void 547c478bd9Sstevel@tonic-gate dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id) 557c478bd9Sstevel@tonic-gate { 567c478bd9Sstevel@tonic-gate dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree]; 577c478bd9Sstevel@tonic-gate uint_t h; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate assert(dmp->dm_symfree < dmp->dm_nsymelems + 1); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate dsp->ds_symid = id; 627c478bd9Sstevel@tonic-gate h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 637c478bd9Sstevel@tonic-gate dsp->ds_next = dmp->dm_symbuckets[h]; 647c478bd9Sstevel@tonic-gate dmp->dm_symbuckets[h] = dmp->dm_symfree++; 657c478bd9Sstevel@tonic-gate } 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static uint_t 687c478bd9Sstevel@tonic-gate dt_module_syminit32(dt_module_t *dmp) 697c478bd9Sstevel@tonic-gate { 7062b628a6SAli Bahrami #if STT_NUM != (STT_TLS + 1) 717e16fca0SAli Bahrami #error "STT_NUM has grown. update dt_module_syminit32()" 727e16fca0SAli Bahrami #endif 737e16fca0SAli Bahrami 747c478bd9Sstevel@tonic-gate const Elf32_Sym *sym = dmp->dm_symtab.cts_data; 757c478bd9Sstevel@tonic-gate const char *base = dmp->dm_strtab.cts_data; 767c478bd9Sstevel@tonic-gate size_t ss_size = dmp->dm_strtab.cts_size; 777c478bd9Sstevel@tonic-gate uint_t i, n = dmp->dm_nsymelems; 787c478bd9Sstevel@tonic-gate uint_t asrsv = 0; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++, sym++) { 817c478bd9Sstevel@tonic-gate const char *name = base + sym->st_name; 827c478bd9Sstevel@tonic-gate uchar_t type = ELF32_ST_TYPE(sym->st_info); 837c478bd9Sstevel@tonic-gate 8462b628a6SAli Bahrami if (type >= STT_NUM || type == STT_SECTION) 857c478bd9Sstevel@tonic-gate continue; /* skip sections and unknown types */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate if (sym->st_name == 0 || sym->st_name >= ss_size) 887c478bd9Sstevel@tonic-gate continue; /* skip null or invalid names */ 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 917c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 927c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in the address map */ 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate dt_module_symhash_insert(dmp, name, i); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate return (asrsv); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static uint_t 1017c478bd9Sstevel@tonic-gate dt_module_syminit64(dt_module_t *dmp) 1027c478bd9Sstevel@tonic-gate { 10362b628a6SAli Bahrami #if STT_NUM != (STT_TLS + 1) 1047e16fca0SAli Bahrami #error "STT_NUM has grown. update dt_module_syminit64()" 1057e16fca0SAli Bahrami #endif 1067e16fca0SAli Bahrami 1077c478bd9Sstevel@tonic-gate const Elf64_Sym *sym = dmp->dm_symtab.cts_data; 1087c478bd9Sstevel@tonic-gate const char *base = dmp->dm_strtab.cts_data; 1097c478bd9Sstevel@tonic-gate size_t ss_size = dmp->dm_strtab.cts_size; 1107c478bd9Sstevel@tonic-gate uint_t i, n = dmp->dm_nsymelems; 1117c478bd9Sstevel@tonic-gate uint_t asrsv = 0; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++, sym++) { 1147c478bd9Sstevel@tonic-gate const char *name = base + sym->st_name; 1157c478bd9Sstevel@tonic-gate uchar_t type = ELF64_ST_TYPE(sym->st_info); 1167c478bd9Sstevel@tonic-gate 11762b628a6SAli Bahrami if (type >= STT_NUM || type == STT_SECTION) 1187c478bd9Sstevel@tonic-gate continue; /* skip sections and unknown types */ 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (sym->st_name == 0 || sym->st_name >= ss_size) 1217c478bd9Sstevel@tonic-gate continue; /* skip null or invalid names */ 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 1247c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 1257c478bd9Sstevel@tonic-gate asrsv++; /* reserve space in the address map */ 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate dt_module_symhash_insert(dmp, name, i); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate return (asrsv); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Sort comparison function for 32-bit symbol address-to-name lookups. We sort 1357c478bd9Sstevel@tonic-gate * symbols by value. If values are equal, we prefer the symbol that is 1367c478bd9Sstevel@tonic-gate * non-zero sized, typed, not weak, or lexically first, in that order. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate static int 1397c478bd9Sstevel@tonic-gate dt_module_symcomp32(const void *lp, const void *rp) 1407c478bd9Sstevel@tonic-gate { 1417c478bd9Sstevel@tonic-gate Elf32_Sym *lhs = *((Elf32_Sym **)lp); 1427c478bd9Sstevel@tonic-gate Elf32_Sym *rhs = *((Elf32_Sym **)rp); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (lhs->st_value != rhs->st_value) 1457c478bd9Sstevel@tonic-gate return (lhs->st_value > rhs->st_value ? 1 : -1); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if ((lhs->st_size == 0) != (rhs->st_size == 0)) 1487c478bd9Sstevel@tonic-gate return (lhs->st_size == 0 ? 1 : -1); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 1517c478bd9Sstevel@tonic-gate (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 1527c478bd9Sstevel@tonic-gate return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != 1557c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) 1567c478bd9Sstevel@tonic-gate return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate return (strcmp(dt_module_strtab + lhs->st_name, 1597c478bd9Sstevel@tonic-gate dt_module_strtab + rhs->st_name)); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * Sort comparison function for 64-bit symbol address-to-name lookups. We sort 1647c478bd9Sstevel@tonic-gate * symbols by value. If values are equal, we prefer the symbol that is 1657c478bd9Sstevel@tonic-gate * non-zero sized, typed, not weak, or lexically first, in that order. 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate static int 1687c478bd9Sstevel@tonic-gate dt_module_symcomp64(const void *lp, const void *rp) 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate Elf64_Sym *lhs = *((Elf64_Sym **)lp); 1717c478bd9Sstevel@tonic-gate Elf64_Sym *rhs = *((Elf64_Sym **)rp); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if (lhs->st_value != rhs->st_value) 1747c478bd9Sstevel@tonic-gate return (lhs->st_value > rhs->st_value ? 1 : -1); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if ((lhs->st_size == 0) != (rhs->st_size == 0)) 1777c478bd9Sstevel@tonic-gate return (lhs->st_size == 0 ? 1 : -1); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 1807c478bd9Sstevel@tonic-gate (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 1817c478bd9Sstevel@tonic-gate return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != 1847c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) 1857c478bd9Sstevel@tonic-gate return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate return (strcmp(dt_module_strtab + lhs->st_name, 1887c478bd9Sstevel@tonic-gate dt_module_strtab + rhs->st_name)); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate static void 1927c478bd9Sstevel@tonic-gate dt_module_symsort32(dt_module_t *dmp) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data; 1957c478bd9Sstevel@tonic-gate Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap; 1967c478bd9Sstevel@tonic-gate const dt_sym_t *dsp = dmp->dm_symchains + 1; 1977c478bd9Sstevel@tonic-gate uint_t i, n = dmp->dm_symfree; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate for (i = 1; i < n; i++, dsp++) { 2007c478bd9Sstevel@tonic-gate Elf32_Sym *sym = symtab + dsp->ds_symid; 2017c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 2027c478bd9Sstevel@tonic-gate (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 2037c478bd9Sstevel@tonic-gate *sympp++ = sym; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap); 2077c478bd9Sstevel@tonic-gate assert(dmp->dm_aslen <= dmp->dm_asrsv); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate dt_module_strtab = dmp->dm_strtab.cts_data; 2107c478bd9Sstevel@tonic-gate qsort(dmp->dm_asmap, dmp->dm_aslen, 2117c478bd9Sstevel@tonic-gate sizeof (Elf32_Sym *), dt_module_symcomp32); 2127c478bd9Sstevel@tonic-gate dt_module_strtab = NULL; 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate static void 2167c478bd9Sstevel@tonic-gate dt_module_symsort64(dt_module_t *dmp) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data; 2197c478bd9Sstevel@tonic-gate Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap; 2207c478bd9Sstevel@tonic-gate const dt_sym_t *dsp = dmp->dm_symchains + 1; 2217c478bd9Sstevel@tonic-gate uint_t i, n = dmp->dm_symfree; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate for (i = 1; i < n; i++, dsp++) { 2247c478bd9Sstevel@tonic-gate Elf64_Sym *sym = symtab + dsp->ds_symid; 2257c478bd9Sstevel@tonic-gate if (sym->st_value != 0 && 2267c478bd9Sstevel@tonic-gate (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 2277c478bd9Sstevel@tonic-gate *sympp++ = sym; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap); 2317c478bd9Sstevel@tonic-gate assert(dmp->dm_aslen <= dmp->dm_asrsv); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate dt_module_strtab = dmp->dm_strtab.cts_data; 2347c478bd9Sstevel@tonic-gate qsort(dmp->dm_asmap, dmp->dm_aslen, 2357c478bd9Sstevel@tonic-gate sizeof (Elf64_Sym *), dt_module_symcomp64); 2367c478bd9Sstevel@tonic-gate dt_module_strtab = NULL; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static GElf_Sym * 2407c478bd9Sstevel@tonic-gate dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate if (dst != NULL) { 2437c478bd9Sstevel@tonic-gate dst->st_name = src->st_name; 2447c478bd9Sstevel@tonic-gate dst->st_info = src->st_info; 2457c478bd9Sstevel@tonic-gate dst->st_other = src->st_other; 2467c478bd9Sstevel@tonic-gate dst->st_shndx = src->st_shndx; 2477c478bd9Sstevel@tonic-gate dst->st_value = src->st_value; 2487c478bd9Sstevel@tonic-gate dst->st_size = src->st_size; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate return (dst); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate static GElf_Sym * 2557c478bd9Sstevel@tonic-gate dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate if (dst != NULL) 2587c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (GElf_Sym)); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate return (dst); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static GElf_Sym * 2647c478bd9Sstevel@tonic-gate dt_module_symname32(dt_module_t *dmp, const char *name, 2657c478bd9Sstevel@tonic-gate GElf_Sym *symp, uint_t *idp) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; 2687c478bd9Sstevel@tonic-gate const char *strtab = dmp->dm_strtab.cts_data; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate const Elf32_Sym *sym; 2717c478bd9Sstevel@tonic-gate const dt_sym_t *dsp; 2727c478bd9Sstevel@tonic-gate uint_t i, h; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (dmp->dm_nsymelems == 0) 2757c478bd9Sstevel@tonic-gate return (NULL); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { 2807c478bd9Sstevel@tonic-gate dsp = &dmp->dm_symchains[i]; 2817c478bd9Sstevel@tonic-gate sym = symtab + dsp->ds_symid; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate if (strcmp(name, strtab + sym->st_name) == 0) { 2847c478bd9Sstevel@tonic-gate if (idp != NULL) 2857c478bd9Sstevel@tonic-gate *idp = dsp->ds_symid; 2867c478bd9Sstevel@tonic-gate return (dt_module_symgelf32(sym, symp)); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate return (NULL); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate static GElf_Sym * 2947c478bd9Sstevel@tonic-gate dt_module_symname64(dt_module_t *dmp, const char *name, 2957c478bd9Sstevel@tonic-gate GElf_Sym *symp, uint_t *idp) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; 2987c478bd9Sstevel@tonic-gate const char *strtab = dmp->dm_strtab.cts_data; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate const Elf64_Sym *sym; 3017c478bd9Sstevel@tonic-gate const dt_sym_t *dsp; 3027c478bd9Sstevel@tonic-gate uint_t i, h; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (dmp->dm_nsymelems == 0) 3057c478bd9Sstevel@tonic-gate return (NULL); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { 3107c478bd9Sstevel@tonic-gate dsp = &dmp->dm_symchains[i]; 3117c478bd9Sstevel@tonic-gate sym = symtab + dsp->ds_symid; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (strcmp(name, strtab + sym->st_name) == 0) { 3147c478bd9Sstevel@tonic-gate if (idp != NULL) 3157c478bd9Sstevel@tonic-gate *idp = dsp->ds_symid; 3167c478bd9Sstevel@tonic-gate return (dt_module_symgelf64(sym, symp)); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate return (NULL); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate static GElf_Sym * 3247c478bd9Sstevel@tonic-gate dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr, 3257c478bd9Sstevel@tonic-gate GElf_Sym *symp, uint_t *idp) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap; 3287c478bd9Sstevel@tonic-gate const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; 3297c478bd9Sstevel@tonic-gate const Elf32_Sym *sym; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; 3327c478bd9Sstevel@tonic-gate Elf32_Addr v; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (dmp->dm_aslen == 0) 3357c478bd9Sstevel@tonic-gate return (NULL); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate while (hi - lo > 1) { 3387c478bd9Sstevel@tonic-gate mid = (lo + hi) / 2; 3397c478bd9Sstevel@tonic-gate if (addr >= asmap[mid]->st_value) 3407c478bd9Sstevel@tonic-gate lo = mid; 3417c478bd9Sstevel@tonic-gate else 3427c478bd9Sstevel@tonic-gate hi = mid; 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate i = addr < asmap[hi]->st_value ? lo : hi; 3467c478bd9Sstevel@tonic-gate sym = asmap[i]; 3477c478bd9Sstevel@tonic-gate v = sym->st_value; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * If the previous entry has the same value, improve our choice. The 3517c478bd9Sstevel@tonic-gate * order of equal-valued symbols is determined by the comparison func. 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate while (i-- != 0 && asmap[i]->st_value == v) 3547c478bd9Sstevel@tonic-gate sym = asmap[i]; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (addr - sym->st_value < MAX(sym->st_size, 1)) { 3577c478bd9Sstevel@tonic-gate if (idp != NULL) 3587c478bd9Sstevel@tonic-gate *idp = (uint_t)(sym - symtab); 3597c478bd9Sstevel@tonic-gate return (dt_module_symgelf32(sym, symp)); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate return (NULL); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate static GElf_Sym * 3667c478bd9Sstevel@tonic-gate dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr, 3677c478bd9Sstevel@tonic-gate GElf_Sym *symp, uint_t *idp) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap; 3707c478bd9Sstevel@tonic-gate const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; 3717c478bd9Sstevel@tonic-gate const Elf64_Sym *sym; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; 3747c478bd9Sstevel@tonic-gate Elf64_Addr v; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if (dmp->dm_aslen == 0) 3777c478bd9Sstevel@tonic-gate return (NULL); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate while (hi - lo > 1) { 3807c478bd9Sstevel@tonic-gate mid = (lo + hi) / 2; 3817c478bd9Sstevel@tonic-gate if (addr >= asmap[mid]->st_value) 3827c478bd9Sstevel@tonic-gate lo = mid; 3837c478bd9Sstevel@tonic-gate else 3847c478bd9Sstevel@tonic-gate hi = mid; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate i = addr < asmap[hi]->st_value ? lo : hi; 3887c478bd9Sstevel@tonic-gate sym = asmap[i]; 3897c478bd9Sstevel@tonic-gate v = sym->st_value; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * If the previous entry has the same value, improve our choice. The 3937c478bd9Sstevel@tonic-gate * order of equal-valued symbols is determined by the comparison func. 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate while (i-- != 0 && asmap[i]->st_value == v) 3967c478bd9Sstevel@tonic-gate sym = asmap[i]; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate if (addr - sym->st_value < MAX(sym->st_size, 1)) { 3997c478bd9Sstevel@tonic-gate if (idp != NULL) 4007c478bd9Sstevel@tonic-gate *idp = (uint_t)(sym - symtab); 4017c478bd9Sstevel@tonic-gate return (dt_module_symgelf64(sym, symp)); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate return (NULL); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate static const dt_modops_t dt_modops_32 = { 4087c478bd9Sstevel@tonic-gate dt_module_syminit32, 4097c478bd9Sstevel@tonic-gate dt_module_symsort32, 4107c478bd9Sstevel@tonic-gate dt_module_symname32, 4117c478bd9Sstevel@tonic-gate dt_module_symaddr32 4127c478bd9Sstevel@tonic-gate }; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate static const dt_modops_t dt_modops_64 = { 4157c478bd9Sstevel@tonic-gate dt_module_syminit64, 4167c478bd9Sstevel@tonic-gate dt_module_symsort64, 4177c478bd9Sstevel@tonic-gate dt_module_symname64, 4187c478bd9Sstevel@tonic-gate dt_module_symaddr64 4197c478bd9Sstevel@tonic-gate }; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate dt_module_t * 4227c478bd9Sstevel@tonic-gate dt_module_create(dtrace_hdl_t *dtp, const char *name) 4237c478bd9Sstevel@tonic-gate { 424*a386cc11SRobert Mustacchi long pid; 425*a386cc11SRobert Mustacchi char *eptr; 426*a386cc11SRobert Mustacchi dt_ident_t *idp; 4277c478bd9Sstevel@tonic-gate uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; 4287c478bd9Sstevel@tonic-gate dt_module_t *dmp; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { 4317c478bd9Sstevel@tonic-gate if (strcmp(dmp->dm_name, name) == 0) 4327c478bd9Sstevel@tonic-gate return (dmp); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if ((dmp = malloc(sizeof (dt_module_t))) == NULL) 4367c478bd9Sstevel@tonic-gate return (NULL); /* caller must handle allocation failure */ 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate bzero(dmp, sizeof (dt_module_t)); 4397c478bd9Sstevel@tonic-gate (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); 4407c478bd9Sstevel@tonic-gate dt_list_append(&dtp->dt_modlist, dmp); 4417c478bd9Sstevel@tonic-gate dmp->dm_next = dtp->dt_mods[h]; 4427c478bd9Sstevel@tonic-gate dtp->dt_mods[h] = dmp; 4437c478bd9Sstevel@tonic-gate dtp->dt_nmods++; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) 4467c478bd9Sstevel@tonic-gate dmp->dm_ops = &dt_modops_64; 4477c478bd9Sstevel@tonic-gate else 4487c478bd9Sstevel@tonic-gate dmp->dm_ops = &dt_modops_32; 4497c478bd9Sstevel@tonic-gate 450*a386cc11SRobert Mustacchi /* 451*a386cc11SRobert Mustacchi * Modules for userland processes are special. They always refer to a 452*a386cc11SRobert Mustacchi * specific process and have a copy of their CTF data from a specific 453*a386cc11SRobert Mustacchi * instant in time. Any dt_module_t that begins with 'pid' is a module 454*a386cc11SRobert Mustacchi * for a specific process, much like how any probe description that 455*a386cc11SRobert Mustacchi * begins with 'pid' is special. pid123 refers to process 123. A module 456*a386cc11SRobert Mustacchi * that is just 'pid' refers specifically to pid$target. This is 457*a386cc11SRobert Mustacchi * generally done as D does not currently allow for macros to be 458*a386cc11SRobert Mustacchi * evaluated when working with types. 459*a386cc11SRobert Mustacchi */ 460*a386cc11SRobert Mustacchi if (strncmp(dmp->dm_name, "pid", 3) == 0) { 461*a386cc11SRobert Mustacchi errno = 0; 462*a386cc11SRobert Mustacchi if (dmp->dm_name[3] == '\0') { 463*a386cc11SRobert Mustacchi idp = dt_idhash_lookup(dtp->dt_macros, "target"); 464*a386cc11SRobert Mustacchi if (idp != NULL && idp->di_id != 0) 465*a386cc11SRobert Mustacchi dmp->dm_pid = idp->di_id; 466*a386cc11SRobert Mustacchi } else { 467*a386cc11SRobert Mustacchi pid = strtol(dmp->dm_name + 3, &eptr, 10); 468*a386cc11SRobert Mustacchi if (errno == 0 && *eptr == '\0') 469*a386cc11SRobert Mustacchi dmp->dm_pid = (pid_t)pid; 470*a386cc11SRobert Mustacchi else 471*a386cc11SRobert Mustacchi dt_dprintf("encountered malformed pid " 472*a386cc11SRobert Mustacchi "module: %s\n", dmp->dm_name); 473*a386cc11SRobert Mustacchi } 474*a386cc11SRobert Mustacchi } 475*a386cc11SRobert Mustacchi 4767c478bd9Sstevel@tonic-gate return (dmp); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate dt_module_t * 4807c478bd9Sstevel@tonic-gate dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name) 4817c478bd9Sstevel@tonic-gate { 4827c478bd9Sstevel@tonic-gate uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; 4837c478bd9Sstevel@tonic-gate dt_module_t *dmp; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { 4867c478bd9Sstevel@tonic-gate if (strcmp(dmp->dm_name, name) == 0) 4877c478bd9Sstevel@tonic-gate return (dmp); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate return (NULL); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4947c478bd9Sstevel@tonic-gate dt_module_t * 4957c478bd9Sstevel@tonic-gate dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate return (ctfp ? ctf_getspecific(ctfp) : NULL); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate static int 5017c478bd9Sstevel@tonic-gate dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate const char *s; 5047c478bd9Sstevel@tonic-gate size_t shstrs; 5057c478bd9Sstevel@tonic-gate GElf_Shdr sh; 5067c478bd9Sstevel@tonic-gate Elf_Data *dp; 5077c478bd9Sstevel@tonic-gate Elf_Scn *sp; 5087c478bd9Sstevel@tonic-gate 50962b628a6SAli Bahrami if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) 5107c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOTLOADED)); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { 5137c478bd9Sstevel@tonic-gate if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || 5147c478bd9Sstevel@tonic-gate (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) 5157c478bd9Sstevel@tonic-gate continue; /* skip any malformed sections */ 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (sh.sh_type == ctsp->cts_type && 5187c478bd9Sstevel@tonic-gate sh.sh_entsize == ctsp->cts_entsize && 5197c478bd9Sstevel@tonic-gate strcmp(s, ctsp->cts_name) == 0) 5207c478bd9Sstevel@tonic-gate break; /* section matches specification */ 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * If the section isn't found, return success but leave cts_data set 5257c478bd9Sstevel@tonic-gate * to NULL and cts_size set to zero for our caller. 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL) 5287c478bd9Sstevel@tonic-gate return (0); 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate ctsp->cts_data = dp->d_buf; 5317c478bd9Sstevel@tonic-gate ctsp->cts_size = dp->d_size; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate dt_dprintf("loaded %s [%s] (%lu bytes)\n", 5347c478bd9Sstevel@tonic-gate dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate return (0); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 539*a386cc11SRobert Mustacchi typedef struct dt_module_cb_arg { 540*a386cc11SRobert Mustacchi struct ps_prochandle *dpa_proc; 541*a386cc11SRobert Mustacchi dtrace_hdl_t *dpa_dtp; 542*a386cc11SRobert Mustacchi dt_module_t *dpa_dmp; 543*a386cc11SRobert Mustacchi uint_t dpa_count; 544*a386cc11SRobert Mustacchi } dt_module_cb_arg_t; 545*a386cc11SRobert Mustacchi 546*a386cc11SRobert Mustacchi /* ARGSUSED */ 547*a386cc11SRobert Mustacchi static int 548*a386cc11SRobert Mustacchi dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj) 549*a386cc11SRobert Mustacchi { 550*a386cc11SRobert Mustacchi ctf_file_t *fp; 551*a386cc11SRobert Mustacchi dt_module_cb_arg_t *dcp = arg; 552*a386cc11SRobert Mustacchi 553*a386cc11SRobert Mustacchi /* Try to grab a ctf container if it exists */ 554*a386cc11SRobert Mustacchi fp = Pname_to_ctf(dcp->dpa_proc, obj); 555*a386cc11SRobert Mustacchi if (fp != NULL) 556*a386cc11SRobert Mustacchi dcp->dpa_count++; 557*a386cc11SRobert Mustacchi return (0); 558*a386cc11SRobert Mustacchi } 559*a386cc11SRobert Mustacchi 560*a386cc11SRobert Mustacchi /* ARGSUSED */ 561*a386cc11SRobert Mustacchi static int 562*a386cc11SRobert Mustacchi dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj) 563*a386cc11SRobert Mustacchi { 564*a386cc11SRobert Mustacchi ctf_file_t *fp; 565*a386cc11SRobert Mustacchi char buf[MAXPATHLEN], *p; 566*a386cc11SRobert Mustacchi dt_module_cb_arg_t *dcp = arg; 567*a386cc11SRobert Mustacchi int count = dcp->dpa_count; 568*a386cc11SRobert Mustacchi Lmid_t lmid; 569*a386cc11SRobert Mustacchi 570*a386cc11SRobert Mustacchi fp = Pname_to_ctf(dcp->dpa_proc, obj); 571*a386cc11SRobert Mustacchi if (fp == NULL) 572*a386cc11SRobert Mustacchi return (0); 573*a386cc11SRobert Mustacchi fp = ctf_dup(fp); 574*a386cc11SRobert Mustacchi if (fp == NULL) 575*a386cc11SRobert Mustacchi return (0); 576*a386cc11SRobert Mustacchi dcp->dpa_dmp->dm_libctfp[count] = fp; 577*a386cc11SRobert Mustacchi /* 578*a386cc11SRobert Mustacchi * While it'd be nice to simply use objname here, because of our prior 579*a386cc11SRobert Mustacchi * actions we'll always get a resolved object name to its on disk file. 580*a386cc11SRobert Mustacchi * Like the pid provider, we need to tell a bit of a lie here. The type 581*a386cc11SRobert Mustacchi * that the user thinks of is in terms of the libraries they requested, 582*a386cc11SRobert Mustacchi * eg. libc.so.1, they don't care about the fact that it's 583*a386cc11SRobert Mustacchi * libc_hwcap.so.1. 584*a386cc11SRobert Mustacchi */ 585*a386cc11SRobert Mustacchi (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf)); 586*a386cc11SRobert Mustacchi if ((p = strrchr(buf, '/')) == NULL) 587*a386cc11SRobert Mustacchi p = buf; 588*a386cc11SRobert Mustacchi else 589*a386cc11SRobert Mustacchi p++; 590*a386cc11SRobert Mustacchi 591*a386cc11SRobert Mustacchi /* 592*a386cc11SRobert Mustacchi * If for some reason we can't find a link map id for this module, which 593*a386cc11SRobert Mustacchi * would be really quite weird. We instead just say the link map id is 594*a386cc11SRobert Mustacchi * zero. 595*a386cc11SRobert Mustacchi */ 596*a386cc11SRobert Mustacchi if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0) 597*a386cc11SRobert Mustacchi lmid = 0; 598*a386cc11SRobert Mustacchi 599*a386cc11SRobert Mustacchi if (lmid == 0) 600*a386cc11SRobert Mustacchi dcp->dpa_dmp->dm_libctfn[count] = strdup(p); 601*a386cc11SRobert Mustacchi else 602*a386cc11SRobert Mustacchi (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count], 603*a386cc11SRobert Mustacchi "LM%lx`%s", lmid, p); 604*a386cc11SRobert Mustacchi if (dcp->dpa_dmp->dm_libctfn[count] == NULL) 605*a386cc11SRobert Mustacchi return (1); 606*a386cc11SRobert Mustacchi ctf_setspecific(fp, dcp->dpa_dmp); 607*a386cc11SRobert Mustacchi dcp->dpa_count++; 608*a386cc11SRobert Mustacchi return (0); 609*a386cc11SRobert Mustacchi } 610*a386cc11SRobert Mustacchi 611*a386cc11SRobert Mustacchi /* 612*a386cc11SRobert Mustacchi * We've been asked to load data that belongs to another process. As such we're 613*a386cc11SRobert Mustacchi * going to pgrab it at this instant, load everything that we might ever care 614*a386cc11SRobert Mustacchi * about, and then drive on. The reason for this is that the process that we're 615*a386cc11SRobert Mustacchi * interested in might be changing. As long as we have grabbed it, then this 616*a386cc11SRobert Mustacchi * can't be a problem for us. 617*a386cc11SRobert Mustacchi * 618*a386cc11SRobert Mustacchi * For now, we're actually going to punt on most things and just try to get CTF 619*a386cc11SRobert Mustacchi * data, nothing else. Basically this is only useful as a source of type 620*a386cc11SRobert Mustacchi * information, we can't go and do the stacktrace lookups, etc. 621*a386cc11SRobert Mustacchi */ 622*a386cc11SRobert Mustacchi static int 623*a386cc11SRobert Mustacchi dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp) 624*a386cc11SRobert Mustacchi { 625*a386cc11SRobert Mustacchi struct ps_prochandle *p; 626*a386cc11SRobert Mustacchi dt_module_cb_arg_t arg; 627*a386cc11SRobert Mustacchi 628*a386cc11SRobert Mustacchi /* 629*a386cc11SRobert Mustacchi * Note that on success we do not release this hold. We must hold this 630*a386cc11SRobert Mustacchi * for our life time. 631*a386cc11SRobert Mustacchi */ 632*a386cc11SRobert Mustacchi p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE); 633*a386cc11SRobert Mustacchi if (p == NULL) { 634*a386cc11SRobert Mustacchi dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid); 635*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_CANTLOAD)); 636*a386cc11SRobert Mustacchi } 637*a386cc11SRobert Mustacchi dt_proc_lock(dtp, p); 638*a386cc11SRobert Mustacchi 639*a386cc11SRobert Mustacchi arg.dpa_proc = p; 640*a386cc11SRobert Mustacchi arg.dpa_dtp = dtp; 641*a386cc11SRobert Mustacchi arg.dpa_dmp = dmp; 642*a386cc11SRobert Mustacchi arg.dpa_count = 0; 643*a386cc11SRobert Mustacchi if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) { 644*a386cc11SRobert Mustacchi dt_dprintf("failed to iterate objects\n"); 645*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 646*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_CANTLOAD)); 647*a386cc11SRobert Mustacchi } 648*a386cc11SRobert Mustacchi 649*a386cc11SRobert Mustacchi if (arg.dpa_count == 0) { 650*a386cc11SRobert Mustacchi dt_dprintf("no ctf data present\n"); 651*a386cc11SRobert Mustacchi dt_proc_unlock(dtp, p); 652*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 653*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_CANTLOAD)); 654*a386cc11SRobert Mustacchi } 655*a386cc11SRobert Mustacchi 656*a386cc11SRobert Mustacchi dmp->dm_libctfp = malloc(sizeof (ctf_file_t *) * arg.dpa_count); 657*a386cc11SRobert Mustacchi if (dmp->dm_libctfp == NULL) { 658*a386cc11SRobert Mustacchi dt_proc_unlock(dtp, p); 659*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 660*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_NOMEM)); 661*a386cc11SRobert Mustacchi } 662*a386cc11SRobert Mustacchi bzero(dmp->dm_libctfp, sizeof (ctf_file_t *) * arg.dpa_count); 663*a386cc11SRobert Mustacchi 664*a386cc11SRobert Mustacchi dmp->dm_libctfn = malloc(sizeof (char *) * arg.dpa_count); 665*a386cc11SRobert Mustacchi if (dmp->dm_libctfn == NULL) { 666*a386cc11SRobert Mustacchi free(dmp->dm_libctfp); 667*a386cc11SRobert Mustacchi dt_proc_unlock(dtp, p); 668*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 669*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_NOMEM)); 670*a386cc11SRobert Mustacchi } 671*a386cc11SRobert Mustacchi bzero(dmp->dm_libctfn, sizeof (char *) * arg.dpa_count); 672*a386cc11SRobert Mustacchi 673*a386cc11SRobert Mustacchi dmp->dm_nctflibs = arg.dpa_count; 674*a386cc11SRobert Mustacchi 675*a386cc11SRobert Mustacchi arg.dpa_count = 0; 676*a386cc11SRobert Mustacchi if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) { 677*a386cc11SRobert Mustacchi dt_proc_unlock(dtp, p); 678*a386cc11SRobert Mustacchi dt_module_unload(dtp, dmp); 679*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 680*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_CANTLOAD)); 681*a386cc11SRobert Mustacchi } 682*a386cc11SRobert Mustacchi assert(arg.dpa_count == dmp->dm_nctflibs); 683*a386cc11SRobert Mustacchi dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count, 684*a386cc11SRobert Mustacchi (int)dmp->dm_pid); 685*a386cc11SRobert Mustacchi 686*a386cc11SRobert Mustacchi dt_proc_unlock(dtp, p); 687*a386cc11SRobert Mustacchi dt_proc_release(dtp, p); 688*a386cc11SRobert Mustacchi dmp->dm_flags |= DT_DM_LOADED; 689*a386cc11SRobert Mustacchi 690*a386cc11SRobert Mustacchi return (0); 691*a386cc11SRobert Mustacchi } 692*a386cc11SRobert Mustacchi 6937c478bd9Sstevel@tonic-gate int 6947c478bd9Sstevel@tonic-gate dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) 6957c478bd9Sstevel@tonic-gate { 6967c478bd9Sstevel@tonic-gate if (dmp->dm_flags & DT_DM_LOADED) 6977c478bd9Sstevel@tonic-gate return (0); /* module is already loaded */ 6987c478bd9Sstevel@tonic-gate 699*a386cc11SRobert Mustacchi if (dmp->dm_pid != 0) 700*a386cc11SRobert Mustacchi return (dt_module_load_proc(dtp, dmp)); 701*a386cc11SRobert Mustacchi 7027c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_name = ".SUNW_ctf"; 7037c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_type = SHT_PROGBITS; 7047c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_flags = 0; 7057c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_data = NULL; 7067c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_size = 0; 7077c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_entsize = 0; 7087c478bd9Sstevel@tonic-gate dmp->dm_ctdata.cts_offset = 0; 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_name = ".symtab"; 7117c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_type = SHT_SYMTAB; 7127c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_flags = 0; 7137c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_data = NULL; 7147c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_size = 0; 7157c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ? 7167c478bd9Sstevel@tonic-gate sizeof (Elf64_Sym) : sizeof (Elf32_Sym); 7177c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_offset = 0; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_name = ".strtab"; 7207c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_type = SHT_STRTAB; 7217c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_flags = 0; 7227c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_data = NULL; 7237c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_size = 0; 7247c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_entsize = 0; 7257c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_offset = 0; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * Attempt to load the module's CTF section, symbol table section, and 7297c478bd9Sstevel@tonic-gate * string table section. Note that modules may not contain CTF data: 7307c478bd9Sstevel@tonic-gate * this will result in a successful load_sect but data of size zero. 7317c478bd9Sstevel@tonic-gate * We will then fail if dt_module_getctf() is called, as shown below. 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 || 7347c478bd9Sstevel@tonic-gate dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 || 7357c478bd9Sstevel@tonic-gate dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) { 7367c478bd9Sstevel@tonic-gate dt_module_unload(dtp, dmp); 7377c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * Allocate the hash chains and hash buckets for symbol name lookup. 7427c478bd9Sstevel@tonic-gate * This is relatively simple since the symbol table is of fixed size 7437c478bd9Sstevel@tonic-gate * and is known in advance. We allocate one extra element since we 7447c478bd9Sstevel@tonic-gate * use element indices instead of pointers and zero is our sentinel. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate dmp->dm_nsymelems = 7477c478bd9Sstevel@tonic-gate dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate dmp->dm_nsymbuckets = _dtrace_strbuckets; 7507c478bd9Sstevel@tonic-gate dmp->dm_symfree = 1; /* first free element is index 1 */ 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets); 7537c478bd9Sstevel@tonic-gate dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) { 7567c478bd9Sstevel@tonic-gate dt_module_unload(dtp, dmp); 7577c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets); 7617c478bd9Sstevel@tonic-gate bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * Iterate over the symbol table data buffer and insert each symbol 7657c478bd9Sstevel@tonic-gate * name into the name hash if the name and type are valid. Then 7667c478bd9Sstevel@tonic-gate * allocate the address map, fill it in, and sort it. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate dt_dprintf("hashed %s [%s] (%u symbols)\n", 7717c478bd9Sstevel@tonic-gate dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) { 7747c478bd9Sstevel@tonic-gate dt_module_unload(dtp, dmp); 7757c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate dmp->dm_ops->do_symsort(dmp); 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate dt_dprintf("sorted %s [%s] (%u symbols)\n", 7817c478bd9Sstevel@tonic-gate dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate dmp->dm_flags |= DT_DM_LOADED; 7847c478bd9Sstevel@tonic-gate return (0); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 787*a386cc11SRobert Mustacchi int 788*a386cc11SRobert Mustacchi dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp) 789*a386cc11SRobert Mustacchi { 790*a386cc11SRobert Mustacchi if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0) 791*a386cc11SRobert Mustacchi return (1); 792*a386cc11SRobert Mustacchi return (dt_module_getctf(dtp, dmp) != NULL); 793*a386cc11SRobert Mustacchi } 794*a386cc11SRobert Mustacchi 7957c478bd9Sstevel@tonic-gate ctf_file_t * 7967c478bd9Sstevel@tonic-gate dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate const char *parent; 7997c478bd9Sstevel@tonic-gate dt_module_t *pmp; 8007c478bd9Sstevel@tonic-gate ctf_file_t *pfp; 8017c478bd9Sstevel@tonic-gate int model; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0) 8047c478bd9Sstevel@tonic-gate return (dmp->dm_ctfp); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (dmp->dm_ops == &dt_modops_64) 8077c478bd9Sstevel@tonic-gate model = CTF_MODEL_LP64; 8087c478bd9Sstevel@tonic-gate else 8097c478bd9Sstevel@tonic-gate model = CTF_MODEL_ILP32; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * If the data model of the module does not match our program data 8137c478bd9Sstevel@tonic-gate * model, then do not permit CTF from this module to be opened and 8147c478bd9Sstevel@tonic-gate * returned to the compiler. If we support mixed data models in the 8157c478bd9Sstevel@tonic-gate * future for combined kernel/user tracing, this can be removed. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if (dtp->dt_conf.dtc_ctfmodel != model) { 8187c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_DATAMODEL); 8197c478bd9Sstevel@tonic-gate return (NULL); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if (dmp->dm_ctdata.cts_size == 0) { 8237c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOCTF); 8247c478bd9Sstevel@tonic-gate return (NULL); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata, 8287c478bd9Sstevel@tonic-gate &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr); 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate if (dmp->dm_ctfp == NULL) { 8317c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_CTF); 8327c478bd9Sstevel@tonic-gate return (NULL); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate (void) ctf_setmodel(dmp->dm_ctfp, model); 8367c478bd9Sstevel@tonic-gate ctf_setspecific(dmp->dm_ctfp, dmp); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) { 8397c478bd9Sstevel@tonic-gate if ((pmp = dt_module_create(dtp, parent)) == NULL || 8407c478bd9Sstevel@tonic-gate (pfp = dt_module_getctf(dtp, pmp)) == NULL) { 8417c478bd9Sstevel@tonic-gate if (pmp == NULL) 8427c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 8437c478bd9Sstevel@tonic-gate goto err; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) { 8477c478bd9Sstevel@tonic-gate dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp); 8487c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_CTF); 8497c478bd9Sstevel@tonic-gate goto err; 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate dt_dprintf("loaded CTF container for %s (%p)\n", 8547c478bd9Sstevel@tonic-gate dmp->dm_name, (void *)dmp->dm_ctfp); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate return (dmp->dm_ctfp); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate err: 8597c478bd9Sstevel@tonic-gate ctf_close(dmp->dm_ctfp); 8607c478bd9Sstevel@tonic-gate dmp->dm_ctfp = NULL; 8617c478bd9Sstevel@tonic-gate return (NULL); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8657c478bd9Sstevel@tonic-gate void 8667c478bd9Sstevel@tonic-gate dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) 8677c478bd9Sstevel@tonic-gate { 868*a386cc11SRobert Mustacchi int i; 869*a386cc11SRobert Mustacchi 8707c478bd9Sstevel@tonic-gate ctf_close(dmp->dm_ctfp); 8717c478bd9Sstevel@tonic-gate dmp->dm_ctfp = NULL; 8727c478bd9Sstevel@tonic-gate 873*a386cc11SRobert Mustacchi if (dmp->dm_libctfp != NULL) { 874*a386cc11SRobert Mustacchi for (i = 0; i < dmp->dm_nctflibs; i++) { 875*a386cc11SRobert Mustacchi ctf_close(dmp->dm_libctfp[i]); 876*a386cc11SRobert Mustacchi free(dmp->dm_libctfn[i]); 877*a386cc11SRobert Mustacchi } 878*a386cc11SRobert Mustacchi free(dmp->dm_libctfp); 879*a386cc11SRobert Mustacchi free(dmp->dm_libctfn); 880*a386cc11SRobert Mustacchi dmp->dm_libctfp = NULL; 881*a386cc11SRobert Mustacchi dmp->dm_nctflibs = 0; 882*a386cc11SRobert Mustacchi } 883*a386cc11SRobert Mustacchi 8847c478bd9Sstevel@tonic-gate bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); 8857c478bd9Sstevel@tonic-gate bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); 8867c478bd9Sstevel@tonic-gate bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate if (dmp->dm_symbuckets != NULL) { 8897c478bd9Sstevel@tonic-gate free(dmp->dm_symbuckets); 8907c478bd9Sstevel@tonic-gate dmp->dm_symbuckets = NULL; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate if (dmp->dm_symchains != NULL) { 8947c478bd9Sstevel@tonic-gate free(dmp->dm_symchains); 8957c478bd9Sstevel@tonic-gate dmp->dm_symchains = NULL; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (dmp->dm_asmap != NULL) { 8997c478bd9Sstevel@tonic-gate free(dmp->dm_asmap); 9007c478bd9Sstevel@tonic-gate dmp->dm_asmap = NULL; 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate dmp->dm_symfree = 0; 9047c478bd9Sstevel@tonic-gate dmp->dm_nsymbuckets = 0; 9057c478bd9Sstevel@tonic-gate dmp->dm_nsymelems = 0; 9067c478bd9Sstevel@tonic-gate dmp->dm_asrsv = 0; 9077c478bd9Sstevel@tonic-gate dmp->dm_aslen = 0; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate dmp->dm_text_va = NULL; 9107c478bd9Sstevel@tonic-gate dmp->dm_text_size = 0; 9117c478bd9Sstevel@tonic-gate dmp->dm_data_va = NULL; 9127c478bd9Sstevel@tonic-gate dmp->dm_data_size = 0; 9137c478bd9Sstevel@tonic-gate dmp->dm_bss_va = NULL; 9147c478bd9Sstevel@tonic-gate dmp->dm_bss_size = 0; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate if (dmp->dm_extern != NULL) { 9177c478bd9Sstevel@tonic-gate dt_idhash_destroy(dmp->dm_extern); 9187c478bd9Sstevel@tonic-gate dmp->dm_extern = NULL; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate (void) elf_end(dmp->dm_elf); 9227c478bd9Sstevel@tonic-gate dmp->dm_elf = NULL; 9237c478bd9Sstevel@tonic-gate 924*a386cc11SRobert Mustacchi dmp->dm_pid = 0; 925*a386cc11SRobert Mustacchi 9267c478bd9Sstevel@tonic-gate dmp->dm_flags &= ~DT_DM_LOADED; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate void 9307c478bd9Sstevel@tonic-gate dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp) 9317c478bd9Sstevel@tonic-gate { 932c9a6ea2eSBryan Cantrill uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets; 933c9a6ea2eSBryan Cantrill dt_module_t **dmpp = &dtp->dt_mods[h]; 934c9a6ea2eSBryan Cantrill 9357c478bd9Sstevel@tonic-gate dt_list_delete(&dtp->dt_modlist, dmp); 9367c478bd9Sstevel@tonic-gate assert(dtp->dt_nmods != 0); 9377c478bd9Sstevel@tonic-gate dtp->dt_nmods--; 9387c478bd9Sstevel@tonic-gate 939c9a6ea2eSBryan Cantrill /* 940c9a6ea2eSBryan Cantrill * Now remove this module from its hash chain. We expect to always 941c9a6ea2eSBryan Cantrill * find the module on its hash chain, so in this loop we assert that 942c9a6ea2eSBryan Cantrill * we don't run off the end of the list. 943c9a6ea2eSBryan Cantrill */ 944c9a6ea2eSBryan Cantrill while (*dmpp != dmp) { 945c9a6ea2eSBryan Cantrill dmpp = &((*dmpp)->dm_next); 946c9a6ea2eSBryan Cantrill assert(*dmpp != NULL); 947c9a6ea2eSBryan Cantrill } 948c9a6ea2eSBryan Cantrill 949c9a6ea2eSBryan Cantrill *dmpp = dmp->dm_next; 950c9a6ea2eSBryan Cantrill 9517c478bd9Sstevel@tonic-gate dt_module_unload(dtp, dmp); 9527c478bd9Sstevel@tonic-gate free(dmp); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * Insert a new external symbol reference into the specified module. The new 9577c478bd9Sstevel@tonic-gate * symbol will be marked as undefined and is assigned a symbol index beyond 9587c478bd9Sstevel@tonic-gate * any existing cached symbols from this module. We use the ident's di_data 9597c478bd9Sstevel@tonic-gate * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate dt_ident_t * 9627c478bd9Sstevel@tonic-gate dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp, 9637c478bd9Sstevel@tonic-gate const char *name, const dtrace_typeinfo_t *tip) 9647c478bd9Sstevel@tonic-gate { 9657c478bd9Sstevel@tonic-gate dtrace_syminfo_t *sip; 9667c478bd9Sstevel@tonic-gate dt_ident_t *idp; 9677c478bd9Sstevel@tonic-gate uint_t id; 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create( 9707c478bd9Sstevel@tonic-gate "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) { 9717c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 9727c478bd9Sstevel@tonic-gate return (NULL); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) { 9767c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_SYMOFLOW); 9777c478bd9Sstevel@tonic-gate return (NULL); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) { 9817c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 9827c478bd9Sstevel@tonic-gate return (NULL); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id, 9867c478bd9Sstevel@tonic-gate _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate if (idp == NULL) { 9897c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 9907c478bd9Sstevel@tonic-gate free(sip); 9917c478bd9Sstevel@tonic-gate return (NULL); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate sip->dts_object = dmp->dm_name; 9957c478bd9Sstevel@tonic-gate sip->dts_name = idp->di_name; 9967c478bd9Sstevel@tonic-gate sip->dts_id = idp->di_id; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate idp->di_data = sip; 9997c478bd9Sstevel@tonic-gate idp->di_ctfp = tip->dtt_ctfp; 10007c478bd9Sstevel@tonic-gate idp->di_type = tip->dtt_type; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate return (idp); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate const char * 10067c478bd9Sstevel@tonic-gate dt_module_modelname(dt_module_t *dmp) 10077c478bd9Sstevel@tonic-gate { 10087c478bd9Sstevel@tonic-gate if (dmp->dm_ops == &dt_modops_64) 10097c478bd9Sstevel@tonic-gate return ("64-bit"); 10107c478bd9Sstevel@tonic-gate else 10117c478bd9Sstevel@tonic-gate return ("32-bit"); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate 1014*a386cc11SRobert Mustacchi /* ARGSUSED */ 1015*a386cc11SRobert Mustacchi int 1016*a386cc11SRobert Mustacchi dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp) 1017*a386cc11SRobert Mustacchi { 1018*a386cc11SRobert Mustacchi int i; 1019*a386cc11SRobert Mustacchi 1020*a386cc11SRobert Mustacchi for (i = 0; i < dmp->dm_nctflibs; i++) { 1021*a386cc11SRobert Mustacchi if (dmp->dm_libctfp[i] == fp) 1022*a386cc11SRobert Mustacchi return (i); 1023*a386cc11SRobert Mustacchi } 1024*a386cc11SRobert Mustacchi 1025*a386cc11SRobert Mustacchi return (-1); 1026*a386cc11SRobert Mustacchi } 1027*a386cc11SRobert Mustacchi 1028*a386cc11SRobert Mustacchi /* ARGSUSED */ 1029*a386cc11SRobert Mustacchi ctf_file_t * 1030*a386cc11SRobert Mustacchi dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name) 1031*a386cc11SRobert Mustacchi { 1032*a386cc11SRobert Mustacchi int i; 1033*a386cc11SRobert Mustacchi 1034*a386cc11SRobert Mustacchi for (i = 0; i < dmp->dm_nctflibs; i++) { 1035*a386cc11SRobert Mustacchi if (strcmp(dmp->dm_libctfn[i], name) == 0) 1036*a386cc11SRobert Mustacchi return (dmp->dm_libctfp[i]); 1037*a386cc11SRobert Mustacchi } 1038*a386cc11SRobert Mustacchi 1039*a386cc11SRobert Mustacchi return (NULL); 1040*a386cc11SRobert Mustacchi } 1041*a386cc11SRobert Mustacchi 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * Update our module cache by adding an entry for the specified module 'name'. 10447c478bd9Sstevel@tonic-gate * We create the dt_module_t and populate it using /system/object/<name>/. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate static void 10477c478bd9Sstevel@tonic-gate dt_module_update(dtrace_hdl_t *dtp, const char *name) 10487c478bd9Sstevel@tonic-gate { 10497c478bd9Sstevel@tonic-gate char fname[MAXPATHLEN]; 10507c478bd9Sstevel@tonic-gate struct stat64 st; 10517c478bd9Sstevel@tonic-gate int fd, err, bits; 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate dt_module_t *dmp; 10547c478bd9Sstevel@tonic-gate const char *s; 10557c478bd9Sstevel@tonic-gate size_t shstrs; 10567c478bd9Sstevel@tonic-gate GElf_Shdr sh; 10577c478bd9Sstevel@tonic-gate Elf_Data *dp; 10587c478bd9Sstevel@tonic-gate Elf_Scn *sp; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate (void) snprintf(fname, sizeof (fname), 10617c478bd9Sstevel@tonic-gate "%s/%s/object", OBJFS_ROOT, name); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 || 10647c478bd9Sstevel@tonic-gate (dmp = dt_module_create(dtp, name)) == NULL) { 10657c478bd9Sstevel@tonic-gate dt_dprintf("failed to open %s: %s\n", fname, strerror(errno)); 10667c478bd9Sstevel@tonic-gate (void) close(fd); 10677c478bd9Sstevel@tonic-gate return; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Since the module can unload out from under us (and /system/object 10727c478bd9Sstevel@tonic-gate * will return ENOENT), tell libelf to cook the entire file now and 10737c478bd9Sstevel@tonic-gate * then close the underlying file descriptor immediately. If this 10747c478bd9Sstevel@tonic-gate * succeeds, we know that we can continue safely using dmp->dm_elf. 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL); 10777c478bd9Sstevel@tonic-gate err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD); 10787c478bd9Sstevel@tonic-gate (void) close(fd); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (dmp->dm_elf == NULL || err == -1 || 108162b628a6SAli Bahrami elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) { 10827c478bd9Sstevel@tonic-gate dt_dprintf("failed to load %s: %s\n", 10837c478bd9Sstevel@tonic-gate fname, elf_errmsg(elf_errno())); 10847c478bd9Sstevel@tonic-gate dt_module_destroy(dtp, dmp); 10857c478bd9Sstevel@tonic-gate return; 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate switch (gelf_getclass(dmp->dm_elf)) { 10897c478bd9Sstevel@tonic-gate case ELFCLASS32: 10907c478bd9Sstevel@tonic-gate dmp->dm_ops = &dt_modops_32; 10917c478bd9Sstevel@tonic-gate bits = 32; 10927c478bd9Sstevel@tonic-gate break; 10937c478bd9Sstevel@tonic-gate case ELFCLASS64: 10947c478bd9Sstevel@tonic-gate dmp->dm_ops = &dt_modops_64; 10957c478bd9Sstevel@tonic-gate bits = 64; 10967c478bd9Sstevel@tonic-gate break; 10977c478bd9Sstevel@tonic-gate default: 10987c478bd9Sstevel@tonic-gate dt_dprintf("failed to load %s: unknown ELF class\n", fname); 10997c478bd9Sstevel@tonic-gate dt_module_destroy(dtp, dmp); 11007c478bd9Sstevel@tonic-gate return; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* 11047c478bd9Sstevel@tonic-gate * Iterate over the section headers locating various sections of 11057c478bd9Sstevel@tonic-gate * interest and use their attributes to flesh out the dt_module_t. 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { 11087c478bd9Sstevel@tonic-gate if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || 11097c478bd9Sstevel@tonic-gate (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) 11107c478bd9Sstevel@tonic-gate continue; /* skip any malformed sections */ 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate if (strcmp(s, ".text") == 0) { 11137c478bd9Sstevel@tonic-gate dmp->dm_text_size = sh.sh_size; 11147c478bd9Sstevel@tonic-gate dmp->dm_text_va = sh.sh_addr; 11157c478bd9Sstevel@tonic-gate } else if (strcmp(s, ".data") == 0) { 11167c478bd9Sstevel@tonic-gate dmp->dm_data_size = sh.sh_size; 11177c478bd9Sstevel@tonic-gate dmp->dm_data_va = sh.sh_addr; 11187c478bd9Sstevel@tonic-gate } else if (strcmp(s, ".bss") == 0) { 11197c478bd9Sstevel@tonic-gate dmp->dm_bss_size = sh.sh_size; 11207c478bd9Sstevel@tonic-gate dmp->dm_bss_va = sh.sh_addr; 11217c478bd9Sstevel@tonic-gate } else if (strcmp(s, ".info") == 0 && 11227c478bd9Sstevel@tonic-gate (dp = elf_getdata(sp, NULL)) != NULL) { 11237c478bd9Sstevel@tonic-gate bcopy(dp->d_buf, &dmp->dm_info, 11247c478bd9Sstevel@tonic-gate MIN(sh.sh_size, sizeof (dmp->dm_info))); 11257c478bd9Sstevel@tonic-gate } else if (strcmp(s, ".filename") == 0 && 11267c478bd9Sstevel@tonic-gate (dp = elf_getdata(sp, NULL)) != NULL) { 11277c478bd9Sstevel@tonic-gate (void) strlcpy(dmp->dm_file, 11287c478bd9Sstevel@tonic-gate dp->d_buf, sizeof (dmp->dm_file)); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate dmp->dm_flags |= DT_DM_KERNEL; 11337c478bd9Sstevel@tonic-gate dmp->dm_modid = (int)OBJFS_MODID(st.st_ino); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (dmp->dm_info.objfs_info_primary) 11367c478bd9Sstevel@tonic-gate dmp->dm_flags |= DT_DM_PRIMARY; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate dt_dprintf("opened %d-bit module %s (%s) [%d]\n", 11397c478bd9Sstevel@tonic-gate bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * Unload all the loaded modules and then refresh the module cache with the 11447c478bd9Sstevel@tonic-gate * latest list of loaded modules and their address ranges. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate void 11477c478bd9Sstevel@tonic-gate dtrace_update(dtrace_hdl_t *dtp) 11487c478bd9Sstevel@tonic-gate { 11497c478bd9Sstevel@tonic-gate dt_module_t *dmp; 11507c478bd9Sstevel@tonic-gate DIR *dirp; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate for (dmp = dt_list_next(&dtp->dt_modlist); 11537c478bd9Sstevel@tonic-gate dmp != NULL; dmp = dt_list_next(dmp)) 11547c478bd9Sstevel@tonic-gate dt_module_unload(dtp, dmp); 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * Open /system/object and attempt to create a libdtrace module for 11587c478bd9Sstevel@tonic-gate * each kernel module that is loaded on the current system. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate if (!(dtp->dt_oflags & DTRACE_O_NOSYS) && 11617c478bd9Sstevel@tonic-gate (dirp = opendir(OBJFS_ROOT)) != NULL) { 11624bc0a2efScasper struct dirent *dp; 11637c478bd9Sstevel@tonic-gate 11644bc0a2efScasper while ((dp = readdir(dirp)) != NULL) { 11657c478bd9Sstevel@tonic-gate if (dp->d_name[0] != '.') 11667c478bd9Sstevel@tonic-gate dt_module_update(dtp, dp->d_name); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate (void) closedir(dirp); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* 11737c478bd9Sstevel@tonic-gate * Look up all the macro identifiers and set di_id to the latest value. 11747c478bd9Sstevel@tonic-gate * This code collaborates with dt_lex.l on the use of di_id. We will 11757c478bd9Sstevel@tonic-gate * need to implement something fancier if we need to support non-ints. 11767c478bd9Sstevel@tonic-gate */ 11777c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid(); 11787c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid(); 11797c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid(); 11807c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid(); 11817c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0); 11827c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid(); 11837c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid(); 11847c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0); 11857c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid(); 11867c478bd9Sstevel@tonic-gate dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid(); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Cache the pointers to the modules representing the base executable 1190ae115bc7Smrj * and the run-time linker in the dtrace client handle. Note that on 1191ae115bc7Smrj * x86 krtld is folded into unix, so if we don't find it, use unix 1192ae115bc7Smrj * instead. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix"); 11957c478bd9Sstevel@tonic-gate dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld"); 1196ae115bc7Smrj if (dtp->dt_rtld == NULL) 1197ae115bc7Smrj dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix"); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * If this is the first time we are initializing the module list, 12017c478bd9Sstevel@tonic-gate * remove the module for genunix from the module list and then move it 12027c478bd9Sstevel@tonic-gate * to the front of the module list. We do this so that type and symbol 12037c478bd9Sstevel@tonic-gate * queries encounter genunix and thereby optimize for the common case 12047c478bd9Sstevel@tonic-gate * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below. 12057c478bd9Sstevel@tonic-gate */ 12067c478bd9Sstevel@tonic-gate if (dtp->dt_exec != NULL && 12077c478bd9Sstevel@tonic-gate dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) { 12087c478bd9Sstevel@tonic-gate dt_list_delete(&dtp->dt_modlist, dtp->dt_exec); 12097c478bd9Sstevel@tonic-gate dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate static dt_module_t * 12147c478bd9Sstevel@tonic-gate dt_module_from_object(dtrace_hdl_t *dtp, const char *object) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate int err = EDT_NOMOD; 12177c478bd9Sstevel@tonic-gate dt_module_t *dmp; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate switch ((uintptr_t)object) { 12207c478bd9Sstevel@tonic-gate case (uintptr_t)DTRACE_OBJ_EXEC: 12217c478bd9Sstevel@tonic-gate dmp = dtp->dt_exec; 12227c478bd9Sstevel@tonic-gate break; 12237c478bd9Sstevel@tonic-gate case (uintptr_t)DTRACE_OBJ_RTLD: 12247c478bd9Sstevel@tonic-gate dmp = dtp->dt_rtld; 12257c478bd9Sstevel@tonic-gate break; 12267c478bd9Sstevel@tonic-gate case (uintptr_t)DTRACE_OBJ_CDEFS: 12277c478bd9Sstevel@tonic-gate dmp = dtp->dt_cdefs; 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate case (uintptr_t)DTRACE_OBJ_DDEFS: 12307c478bd9Sstevel@tonic-gate dmp = dtp->dt_ddefs; 12317c478bd9Sstevel@tonic-gate break; 12327c478bd9Sstevel@tonic-gate default: 12337c478bd9Sstevel@tonic-gate dmp = dt_module_create(dtp, object); 12347c478bd9Sstevel@tonic-gate err = EDT_NOMEM; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate if (dmp == NULL) 12387c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, err); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate return (dmp); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * Exported interface to look up a symbol by name. We return the GElf_Sym and 12457c478bd9Sstevel@tonic-gate * complete symbol information for the matching symbol. 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate int 12487c478bd9Sstevel@tonic-gate dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name, 12497c478bd9Sstevel@tonic-gate GElf_Sym *symp, dtrace_syminfo_t *sip) 12507c478bd9Sstevel@tonic-gate { 12517c478bd9Sstevel@tonic-gate dt_module_t *dmp; 12527c478bd9Sstevel@tonic-gate dt_ident_t *idp; 12537c478bd9Sstevel@tonic-gate uint_t n, id; 12547c478bd9Sstevel@tonic-gate GElf_Sym sym; 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate uint_t mask = 0; /* mask of dt_module flags to match */ 12577c478bd9Sstevel@tonic-gate uint_t bits = 0; /* flag bits that must be present */ 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if (object != DTRACE_OBJ_EVERY && 12607c478bd9Sstevel@tonic-gate object != DTRACE_OBJ_KMODS && 12617c478bd9Sstevel@tonic-gate object != DTRACE_OBJ_UMODS) { 12627c478bd9Sstevel@tonic-gate if ((dmp = dt_module_from_object(dtp, object)) == NULL) 12637c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate if (dt_module_load(dtp, dmp) == -1) 12667c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 12677c478bd9Sstevel@tonic-gate n = 1; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate } else { 12707c478bd9Sstevel@tonic-gate if (object == DTRACE_OBJ_KMODS) 12717c478bd9Sstevel@tonic-gate mask = bits = DT_DM_KERNEL; 12727c478bd9Sstevel@tonic-gate else if (object == DTRACE_OBJ_UMODS) 12737c478bd9Sstevel@tonic-gate mask = DT_DM_KERNEL; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate dmp = dt_list_next(&dtp->dt_modlist); 12767c478bd9Sstevel@tonic-gate n = dtp->dt_nmods; 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate if (symp == NULL) 12807c478bd9Sstevel@tonic-gate symp = &sym; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate for (; n > 0; n--, dmp = dt_list_next(dmp)) { 12837c478bd9Sstevel@tonic-gate if ((dmp->dm_flags & mask) != bits) 12847c478bd9Sstevel@tonic-gate continue; /* failed to match required attributes */ 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (dt_module_load(dtp, dmp) == -1) 12877c478bd9Sstevel@tonic-gate continue; /* failed to load symbol table */ 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) { 12907c478bd9Sstevel@tonic-gate if (sip != NULL) { 12917c478bd9Sstevel@tonic-gate sip->dts_object = dmp->dm_name; 12927c478bd9Sstevel@tonic-gate sip->dts_name = (const char *) 12937c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_data + symp->st_name; 12947c478bd9Sstevel@tonic-gate sip->dts_id = id; 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate return (0); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate if (dmp->dm_extern != NULL && 13007c478bd9Sstevel@tonic-gate (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) { 13017c478bd9Sstevel@tonic-gate if (symp != &sym) { 13027c478bd9Sstevel@tonic-gate symp->st_name = (uintptr_t)idp->di_name; 13037c478bd9Sstevel@tonic-gate symp->st_info = 13047c478bd9Sstevel@tonic-gate GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); 13057c478bd9Sstevel@tonic-gate symp->st_other = 0; 13067c478bd9Sstevel@tonic-gate symp->st_shndx = SHN_UNDEF; 13077c478bd9Sstevel@tonic-gate symp->st_value = 0; 13087c478bd9Sstevel@tonic-gate symp->st_size = 13097c478bd9Sstevel@tonic-gate ctf_type_size(idp->di_ctfp, idp->di_type); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (sip != NULL) { 13137c478bd9Sstevel@tonic-gate sip->dts_object = dmp->dm_name; 13147c478bd9Sstevel@tonic-gate sip->dts_name = idp->di_name; 13157c478bd9Sstevel@tonic-gate sip->dts_id = idp->di_id; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate return (0); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOSYM)); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * Exported interface to look up a symbol by address. We return the GElf_Sym 13277c478bd9Sstevel@tonic-gate * and complete symbol information for the matching symbol. 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate int 13307c478bd9Sstevel@tonic-gate dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr, 13317c478bd9Sstevel@tonic-gate GElf_Sym *symp, dtrace_syminfo_t *sip) 13327c478bd9Sstevel@tonic-gate { 13337c478bd9Sstevel@tonic-gate dt_module_t *dmp; 13347c478bd9Sstevel@tonic-gate uint_t id; 13357c478bd9Sstevel@tonic-gate const dtrace_vector_t *v = dtp->dt_vector; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (v != NULL) 13387c478bd9Sstevel@tonic-gate return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip)); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; 13417c478bd9Sstevel@tonic-gate dmp = dt_list_next(dmp)) { 13427c478bd9Sstevel@tonic-gate if (addr - dmp->dm_text_va < dmp->dm_text_size || 13437c478bd9Sstevel@tonic-gate addr - dmp->dm_data_va < dmp->dm_data_size || 13447c478bd9Sstevel@tonic-gate addr - dmp->dm_bss_va < dmp->dm_bss_size) 13457c478bd9Sstevel@tonic-gate break; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if (dmp == NULL) 13497c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOSYMADDR)); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate if (dt_module_load(dtp, dmp) == -1) 13527c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate if (symp != NULL) { 13557c478bd9Sstevel@tonic-gate if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL) 13567c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOSYMADDR)); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate if (sip != NULL) { 13607c478bd9Sstevel@tonic-gate sip->dts_object = dmp->dm_name; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (symp != NULL) { 13637c478bd9Sstevel@tonic-gate sip->dts_name = (const char *) 13647c478bd9Sstevel@tonic-gate dmp->dm_strtab.cts_data + symp->st_name; 13657c478bd9Sstevel@tonic-gate sip->dts_id = id; 13667c478bd9Sstevel@tonic-gate } else { 13677c478bd9Sstevel@tonic-gate sip->dts_name = NULL; 13687c478bd9Sstevel@tonic-gate sip->dts_id = 0; 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate return (0); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate int 13767c478bd9Sstevel@tonic-gate dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, 13777c478bd9Sstevel@tonic-gate dtrace_typeinfo_t *tip) 13787c478bd9Sstevel@tonic-gate { 13797c478bd9Sstevel@tonic-gate dtrace_typeinfo_t ti; 13807c478bd9Sstevel@tonic-gate dt_module_t *dmp; 13817c478bd9Sstevel@tonic-gate int found = 0; 13827c478bd9Sstevel@tonic-gate ctf_id_t id; 1383*a386cc11SRobert Mustacchi uint_t n, i; 1384038dc6b3Sahl int justone; 1385*a386cc11SRobert Mustacchi ctf_file_t *fp; 1386*a386cc11SRobert Mustacchi char *buf, *p, *q; 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate uint_t mask = 0; /* mask of dt_module flags to match */ 13897c478bd9Sstevel@tonic-gate uint_t bits = 0; /* flag bits that must be present */ 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate if (object != DTRACE_OBJ_EVERY && 13927c478bd9Sstevel@tonic-gate object != DTRACE_OBJ_KMODS && 13937c478bd9Sstevel@tonic-gate object != DTRACE_OBJ_UMODS) { 13947c478bd9Sstevel@tonic-gate if ((dmp = dt_module_from_object(dtp, object)) == NULL) 13957c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate if (dt_module_load(dtp, dmp) == -1) 13987c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 13997c478bd9Sstevel@tonic-gate n = 1; 1400038dc6b3Sahl justone = 1; 14017c478bd9Sstevel@tonic-gate } else { 14027c478bd9Sstevel@tonic-gate if (object == DTRACE_OBJ_KMODS) 14037c478bd9Sstevel@tonic-gate mask = bits = DT_DM_KERNEL; 14047c478bd9Sstevel@tonic-gate else if (object == DTRACE_OBJ_UMODS) 14057c478bd9Sstevel@tonic-gate mask = DT_DM_KERNEL; 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate dmp = dt_list_next(&dtp->dt_modlist); 14087c478bd9Sstevel@tonic-gate n = dtp->dt_nmods; 1409038dc6b3Sahl justone = 0; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate if (tip == NULL) 14137c478bd9Sstevel@tonic-gate tip = &ti; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate for (; n > 0; n--, dmp = dt_list_next(dmp)) { 14167c478bd9Sstevel@tonic-gate if ((dmp->dm_flags & mask) != bits) 14177c478bd9Sstevel@tonic-gate continue; /* failed to match required attributes */ 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate /* 14207c478bd9Sstevel@tonic-gate * If we can't load the CTF container, continue on to the next 1421038dc6b3Sahl * module. If our search was scoped to only one module then 1422038dc6b3Sahl * return immediately leaving dt_errno unmodified. 14237c478bd9Sstevel@tonic-gate */ 1424*a386cc11SRobert Mustacchi if (dt_module_hasctf(dtp, dmp) == 0) { 1425038dc6b3Sahl if (justone) 14267c478bd9Sstevel@tonic-gate return (-1); 14277c478bd9Sstevel@tonic-gate continue; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * Look up the type in the module's CTF container. If our 14327c478bd9Sstevel@tonic-gate * match is a forward declaration tag, save this choice in 14337c478bd9Sstevel@tonic-gate * 'tip' and keep going in the hope that we will locate the 14347c478bd9Sstevel@tonic-gate * underlying structure definition. Otherwise just return. 14357c478bd9Sstevel@tonic-gate */ 1436*a386cc11SRobert Mustacchi if (dmp->dm_pid == 0) { 1437*a386cc11SRobert Mustacchi id = ctf_lookup_by_name(dmp->dm_ctfp, name); 1438*a386cc11SRobert Mustacchi fp = dmp->dm_ctfp; 1439*a386cc11SRobert Mustacchi } else { 1440*a386cc11SRobert Mustacchi if ((p = strchr(name, '`')) != NULL) { 1441*a386cc11SRobert Mustacchi buf = strdup(name); 1442*a386cc11SRobert Mustacchi if (buf == NULL) 1443*a386cc11SRobert Mustacchi return (dt_set_errno(dtp, EDT_NOMEM)); 1444*a386cc11SRobert Mustacchi p = strchr(buf, '`'); 1445*a386cc11SRobert Mustacchi if ((q = strchr(p + 1, '`')) != NULL) 1446*a386cc11SRobert Mustacchi p = q; 1447*a386cc11SRobert Mustacchi *p = '\0'; 1448*a386cc11SRobert Mustacchi fp = dt_module_getctflib(dtp, dmp, buf); 1449*a386cc11SRobert Mustacchi if (fp == NULL || (id = ctf_lookup_by_name(fp, 1450*a386cc11SRobert Mustacchi p + 1)) == CTF_ERR) 1451*a386cc11SRobert Mustacchi id = CTF_ERR; 1452*a386cc11SRobert Mustacchi free(buf); 1453*a386cc11SRobert Mustacchi } else { 1454*a386cc11SRobert Mustacchi for (i = 0; i < dmp->dm_nctflibs; i++) { 1455*a386cc11SRobert Mustacchi fp = dmp->dm_libctfp[i]; 1456*a386cc11SRobert Mustacchi id = ctf_lookup_by_name(fp, name); 1457*a386cc11SRobert Mustacchi if (id != CTF_ERR) 1458*a386cc11SRobert Mustacchi break; 1459*a386cc11SRobert Mustacchi } 1460*a386cc11SRobert Mustacchi } 1461*a386cc11SRobert Mustacchi } 1462*a386cc11SRobert Mustacchi if (id != CTF_ERR) { 14637c478bd9Sstevel@tonic-gate tip->dtt_object = dmp->dm_name; 1464*a386cc11SRobert Mustacchi tip->dtt_ctfp = fp; 14657c478bd9Sstevel@tonic-gate tip->dtt_type = id; 1466*a386cc11SRobert Mustacchi if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) != 1467*a386cc11SRobert Mustacchi CTF_K_FORWARD) 14687c478bd9Sstevel@tonic-gate return (0); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate found++; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (found == 0) 14757c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOTYPE)); 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate return (0); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate int 14817c478bd9Sstevel@tonic-gate dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp, 14827c478bd9Sstevel@tonic-gate const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip) 14837c478bd9Sstevel@tonic-gate { 14847c478bd9Sstevel@tonic-gate dt_module_t *dmp; 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate tip->dtt_object = NULL; 14877c478bd9Sstevel@tonic-gate tip->dtt_ctfp = NULL; 14887c478bd9Sstevel@tonic-gate tip->dtt_type = CTF_ERR; 1489*a386cc11SRobert Mustacchi tip->dtt_flags = 0; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) 14927c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMOD)); 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) { 14957c478bd9Sstevel@tonic-gate dt_ident_t *idp = 14967c478bd9Sstevel@tonic-gate dt_idhash_lookup(dmp->dm_extern, sip->dts_name); 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate if (idp == NULL) 14997c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOSYM)); 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate tip->dtt_ctfp = idp->di_ctfp; 15027c478bd9Sstevel@tonic-gate tip->dtt_type = idp->di_type; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) { 15057c478bd9Sstevel@tonic-gate if (dt_module_getctf(dtp, dmp) == NULL) 15067c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate tip->dtt_ctfp = dmp->dm_ctfp; 15097c478bd9Sstevel@tonic-gate tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id); 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate if (tip->dtt_type == CTF_ERR) { 15127c478bd9Sstevel@tonic-gate dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp); 15137c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_CTF)); 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate tip->dtt_ctfp = DT_FPTR_CTFP(dtp); 15187c478bd9Sstevel@tonic-gate tip->dtt_type = DT_FPTR_TYPE(dtp); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate tip->dtt_object = dmp->dm_name; 15227c478bd9Sstevel@tonic-gate return (0); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate static dtrace_objinfo_t * 15267c478bd9Sstevel@tonic-gate dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto) 15277c478bd9Sstevel@tonic-gate { 15287c478bd9Sstevel@tonic-gate dto->dto_name = dmp->dm_name; 15297c478bd9Sstevel@tonic-gate dto->dto_file = dmp->dm_file; 15307c478bd9Sstevel@tonic-gate dto->dto_id = dmp->dm_modid; 15317c478bd9Sstevel@tonic-gate dto->dto_flags = 0; 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate if (dmp->dm_flags & DT_DM_KERNEL) 15347c478bd9Sstevel@tonic-gate dto->dto_flags |= DTRACE_OBJ_F_KERNEL; 15357c478bd9Sstevel@tonic-gate if (dmp->dm_flags & DT_DM_PRIMARY) 15367c478bd9Sstevel@tonic-gate dto->dto_flags |= DTRACE_OBJ_F_PRIMARY; 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate dto->dto_text_va = dmp->dm_text_va; 15397c478bd9Sstevel@tonic-gate dto->dto_text_size = dmp->dm_text_size; 15407c478bd9Sstevel@tonic-gate dto->dto_data_va = dmp->dm_data_va; 15417c478bd9Sstevel@tonic-gate dto->dto_data_size = dmp->dm_data_size; 15427c478bd9Sstevel@tonic-gate dto->dto_bss_va = dmp->dm_bss_va; 15437c478bd9Sstevel@tonic-gate dto->dto_bss_size = dmp->dm_bss_size; 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate return (dto); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate int 15497c478bd9Sstevel@tonic-gate dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist); 15527c478bd9Sstevel@tonic-gate dtrace_objinfo_t dto; 15537c478bd9Sstevel@tonic-gate int rv; 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate for (; dmp != NULL; dmp = dt_list_next(dmp)) { 15567c478bd9Sstevel@tonic-gate if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0) 15577c478bd9Sstevel@tonic-gate return (rv); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate return (0); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate int 15647c478bd9Sstevel@tonic-gate dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto) 15657c478bd9Sstevel@tonic-gate { 15667c478bd9Sstevel@tonic-gate dt_module_t *dmp; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS || 15697c478bd9Sstevel@tonic-gate object == DTRACE_OBJ_UMODS || dto == NULL) 15707c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate if ((dmp = dt_module_from_object(dtp, object)) == NULL) 15737c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (dt_module_load(dtp, dmp) == -1) 15767c478bd9Sstevel@tonic-gate return (-1); /* dt_errno is set for us */ 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate (void) dt_module_info(dmp, dto); 15797c478bd9Sstevel@tonic-gate return (0); 15807c478bd9Sstevel@tonic-gate } 1581