16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License (the "License"). 66ff6d951SJohn Birrell * You may not use this file except in compliance with the License. 76ff6d951SJohn Birrell * 86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 106ff6d951SJohn Birrell * See the License for the specific language governing permissions 116ff6d951SJohn Birrell * and limitations under the License. 126ff6d951SJohn Birrell * 136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 186ff6d951SJohn Birrell * 196ff6d951SJohn Birrell * CDDL HEADER END 206ff6d951SJohn Birrell */ 216ff6d951SJohn Birrell 221670a1c2SRui Paulo /* 231670a1c2SRui Paulo * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 241670a1c2SRui Paulo */ 258e648814SRui Paulo /* 268e648814SRui Paulo * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27273df429SPedro F. Giffuni * Copyright (c) 2016, Pedro Giffuni. All rights reserved. 288e648814SRui Paulo */ 296ff6d951SJohn Birrell 306ff6d951SJohn Birrell #include <sys/types.h> 31bc96366cSSteven Hartland #ifdef illumos 326ff6d951SJohn Birrell #include <sys/modctl.h> 336ff6d951SJohn Birrell #include <sys/kobj.h> 346ff6d951SJohn Birrell #include <sys/kobj_impl.h> 356ff6d951SJohn Birrell #include <sys/sysmacros.h> 366ff6d951SJohn Birrell #include <sys/elf.h> 376ff6d951SJohn Birrell #include <sys/task.h> 38f1e56186SJohn Birrell #else 39f1e56186SJohn Birrell #include <sys/param.h> 40f1e56186SJohn Birrell #include <sys/linker.h> 418436cb81SMark Johnston #include <sys/module.h> 42f1e56186SJohn Birrell #include <sys/stat.h> 43f1e56186SJohn Birrell #endif 446ff6d951SJohn Birrell 456ff6d951SJohn Birrell #include <unistd.h> 46bc96366cSSteven Hartland #ifdef illumos 476ff6d951SJohn Birrell #include <project.h> 48f1e56186SJohn Birrell #endif 496ff6d951SJohn Birrell #include <strings.h> 506ff6d951SJohn Birrell #include <stdlib.h> 516ff6d951SJohn Birrell #include <libelf.h> 526ff6d951SJohn Birrell #include <limits.h> 536ff6d951SJohn Birrell #include <assert.h> 546ff6d951SJohn Birrell #include <errno.h> 556ff6d951SJohn Birrell #include <dirent.h> 56bc96366cSSteven Hartland #ifndef illumos 57f1e56186SJohn Birrell #include <fcntl.h> 588e648814SRui Paulo #include <libproc_compat.h> 59f1e56186SJohn Birrell #endif 606ff6d951SJohn Birrell 616ff6d951SJohn Birrell #include <dt_strtab.h> 626ff6d951SJohn Birrell #include <dt_module.h> 636ff6d951SJohn Birrell #include <dt_impl.h> 646ff6d951SJohn Birrell 656ff6d951SJohn Birrell static const char *dt_module_strtab; /* active strtab for qsort callbacks */ 666ff6d951SJohn Birrell 676ff6d951SJohn Birrell static void 686ff6d951SJohn Birrell dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id) 696ff6d951SJohn Birrell { 706ff6d951SJohn Birrell dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree]; 716ff6d951SJohn Birrell uint_t h; 726ff6d951SJohn Birrell 736ff6d951SJohn Birrell assert(dmp->dm_symfree < dmp->dm_nsymelems + 1); 746ff6d951SJohn Birrell 756ff6d951SJohn Birrell dsp->ds_symid = id; 766ff6d951SJohn Birrell h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 776ff6d951SJohn Birrell dsp->ds_next = dmp->dm_symbuckets[h]; 786ff6d951SJohn Birrell dmp->dm_symbuckets[h] = dmp->dm_symfree++; 796ff6d951SJohn Birrell } 806ff6d951SJohn Birrell 816ff6d951SJohn Birrell static uint_t 826ff6d951SJohn Birrell dt_module_syminit32(dt_module_t *dmp) 836ff6d951SJohn Birrell { 841670a1c2SRui Paulo #if STT_NUM != (STT_TLS + 1) 851670a1c2SRui Paulo #error "STT_NUM has grown. update dt_module_syminit32()" 861670a1c2SRui Paulo #endif 871670a1c2SRui Paulo 88f1e56186SJohn Birrell Elf32_Sym *sym = dmp->dm_symtab.cts_data; 896ff6d951SJohn Birrell const char *base = dmp->dm_strtab.cts_data; 906ff6d951SJohn Birrell size_t ss_size = dmp->dm_strtab.cts_size; 916ff6d951SJohn Birrell uint_t i, n = dmp->dm_nsymelems; 926ff6d951SJohn Birrell uint_t asrsv = 0; 936ff6d951SJohn Birrell 94556cb98dSAndriy Gapon #if defined(__FreeBSD__) 95556cb98dSAndriy Gapon GElf_Ehdr ehdr; 96556cb98dSAndriy Gapon int is_elf_obj; 97556cb98dSAndriy Gapon 98556cb98dSAndriy Gapon gelf_getehdr(dmp->dm_elf, &ehdr); 99556cb98dSAndriy Gapon is_elf_obj = (ehdr.e_type == ET_REL); 100556cb98dSAndriy Gapon #endif 101556cb98dSAndriy Gapon 1026ff6d951SJohn Birrell for (i = 0; i < n; i++, sym++) { 1036ff6d951SJohn Birrell const char *name = base + sym->st_name; 1046ff6d951SJohn Birrell uchar_t type = ELF32_ST_TYPE(sym->st_info); 1056ff6d951SJohn Birrell 1066ff6d951SJohn Birrell if (type >= STT_NUM || type == STT_SECTION) 1076ff6d951SJohn Birrell continue; /* skip sections and unknown types */ 1086ff6d951SJohn Birrell 1096ff6d951SJohn Birrell if (sym->st_name == 0 || sym->st_name >= ss_size) 1106ff6d951SJohn Birrell continue; /* skip null or invalid names */ 1116ff6d951SJohn Birrell 1126ff6d951SJohn Birrell if (sym->st_value != 0 && 113f1e56186SJohn Birrell (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { 1146ff6d951SJohn Birrell asrsv++; /* reserve space in the address map */ 1156ff6d951SJohn Birrell 116556cb98dSAndriy Gapon #if defined(__FreeBSD__) 117f1e56186SJohn Birrell sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; 118556cb98dSAndriy Gapon if (is_elf_obj && sym->st_shndx != SHN_UNDEF && 119556cb98dSAndriy Gapon sym->st_shndx < ehdr.e_shnum) 120556cb98dSAndriy Gapon sym->st_value += 121556cb98dSAndriy Gapon dmp->dm_sec_offsets[sym->st_shndx]; 122f1e56186SJohn Birrell #endif 123f1e56186SJohn Birrell } 124f1e56186SJohn Birrell 1256ff6d951SJohn Birrell dt_module_symhash_insert(dmp, name, i); 1266ff6d951SJohn Birrell } 1276ff6d951SJohn Birrell 1286ff6d951SJohn Birrell return (asrsv); 1296ff6d951SJohn Birrell } 1306ff6d951SJohn Birrell 1316ff6d951SJohn Birrell static uint_t 1326ff6d951SJohn Birrell dt_module_syminit64(dt_module_t *dmp) 1336ff6d951SJohn Birrell { 1341670a1c2SRui Paulo #if STT_NUM != (STT_TLS + 1) 1351670a1c2SRui Paulo #error "STT_NUM has grown. update dt_module_syminit64()" 1361670a1c2SRui Paulo #endif 1371670a1c2SRui Paulo 138f1e56186SJohn Birrell Elf64_Sym *sym = dmp->dm_symtab.cts_data; 1396ff6d951SJohn Birrell const char *base = dmp->dm_strtab.cts_data; 1406ff6d951SJohn Birrell size_t ss_size = dmp->dm_strtab.cts_size; 1416ff6d951SJohn Birrell uint_t i, n = dmp->dm_nsymelems; 1426ff6d951SJohn Birrell uint_t asrsv = 0; 1436ff6d951SJohn Birrell 144556cb98dSAndriy Gapon #if defined(__FreeBSD__) 145556cb98dSAndriy Gapon GElf_Ehdr ehdr; 146556cb98dSAndriy Gapon int is_elf_obj; 147556cb98dSAndriy Gapon 148556cb98dSAndriy Gapon gelf_getehdr(dmp->dm_elf, &ehdr); 149556cb98dSAndriy Gapon is_elf_obj = (ehdr.e_type == ET_REL); 150556cb98dSAndriy Gapon #endif 151556cb98dSAndriy Gapon 1526ff6d951SJohn Birrell for (i = 0; i < n; i++, sym++) { 1536ff6d951SJohn Birrell const char *name = base + sym->st_name; 1546ff6d951SJohn Birrell uchar_t type = ELF64_ST_TYPE(sym->st_info); 1556ff6d951SJohn Birrell 1566ff6d951SJohn Birrell if (type >= STT_NUM || type == STT_SECTION) 1576ff6d951SJohn Birrell continue; /* skip sections and unknown types */ 1586ff6d951SJohn Birrell 1596ff6d951SJohn Birrell if (sym->st_name == 0 || sym->st_name >= ss_size) 1606ff6d951SJohn Birrell continue; /* skip null or invalid names */ 1616ff6d951SJohn Birrell 1626ff6d951SJohn Birrell if (sym->st_value != 0 && 163f1e56186SJohn Birrell (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { 1646ff6d951SJohn Birrell asrsv++; /* reserve space in the address map */ 165556cb98dSAndriy Gapon #if defined(__FreeBSD__) 166f1e56186SJohn Birrell sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; 167556cb98dSAndriy Gapon if (is_elf_obj && sym->st_shndx != SHN_UNDEF && 168556cb98dSAndriy Gapon sym->st_shndx < ehdr.e_shnum) 169556cb98dSAndriy Gapon sym->st_value += 170556cb98dSAndriy Gapon dmp->dm_sec_offsets[sym->st_shndx]; 171f1e56186SJohn Birrell #endif 172f1e56186SJohn Birrell } 173f1e56186SJohn Birrell 1746ff6d951SJohn Birrell dt_module_symhash_insert(dmp, name, i); 1756ff6d951SJohn Birrell } 1766ff6d951SJohn Birrell 1776ff6d951SJohn Birrell return (asrsv); 1786ff6d951SJohn Birrell } 1796ff6d951SJohn Birrell 1806ff6d951SJohn Birrell /* 1816ff6d951SJohn Birrell * Sort comparison function for 32-bit symbol address-to-name lookups. We sort 1826ff6d951SJohn Birrell * symbols by value. If values are equal, we prefer the symbol that is 1836ff6d951SJohn Birrell * non-zero sized, typed, not weak, or lexically first, in that order. 1846ff6d951SJohn Birrell */ 1856ff6d951SJohn Birrell static int 1866ff6d951SJohn Birrell dt_module_symcomp32(const void *lp, const void *rp) 1876ff6d951SJohn Birrell { 1886ff6d951SJohn Birrell Elf32_Sym *lhs = *((Elf32_Sym **)lp); 1896ff6d951SJohn Birrell Elf32_Sym *rhs = *((Elf32_Sym **)rp); 1906ff6d951SJohn Birrell 1916ff6d951SJohn Birrell if (lhs->st_value != rhs->st_value) 1926ff6d951SJohn Birrell return (lhs->st_value > rhs->st_value ? 1 : -1); 1936ff6d951SJohn Birrell 1946ff6d951SJohn Birrell if ((lhs->st_size == 0) != (rhs->st_size == 0)) 1956ff6d951SJohn Birrell return (lhs->st_size == 0 ? 1 : -1); 1966ff6d951SJohn Birrell 1976ff6d951SJohn Birrell if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 1986ff6d951SJohn Birrell (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 1996ff6d951SJohn Birrell return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 2006ff6d951SJohn Birrell 2016ff6d951SJohn Birrell if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != 2026ff6d951SJohn Birrell (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) 2036ff6d951SJohn Birrell return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 2046ff6d951SJohn Birrell 2056ff6d951SJohn Birrell return (strcmp(dt_module_strtab + lhs->st_name, 2066ff6d951SJohn Birrell dt_module_strtab + rhs->st_name)); 2076ff6d951SJohn Birrell } 2086ff6d951SJohn Birrell 2096ff6d951SJohn Birrell /* 2106ff6d951SJohn Birrell * Sort comparison function for 64-bit symbol address-to-name lookups. We sort 2116ff6d951SJohn Birrell * symbols by value. If values are equal, we prefer the symbol that is 2126ff6d951SJohn Birrell * non-zero sized, typed, not weak, or lexically first, in that order. 2136ff6d951SJohn Birrell */ 2146ff6d951SJohn Birrell static int 2156ff6d951SJohn Birrell dt_module_symcomp64(const void *lp, const void *rp) 2166ff6d951SJohn Birrell { 2176ff6d951SJohn Birrell Elf64_Sym *lhs = *((Elf64_Sym **)lp); 2186ff6d951SJohn Birrell Elf64_Sym *rhs = *((Elf64_Sym **)rp); 2196ff6d951SJohn Birrell 2206ff6d951SJohn Birrell if (lhs->st_value != rhs->st_value) 2216ff6d951SJohn Birrell return (lhs->st_value > rhs->st_value ? 1 : -1); 2226ff6d951SJohn Birrell 2236ff6d951SJohn Birrell if ((lhs->st_size == 0) != (rhs->st_size == 0)) 2246ff6d951SJohn Birrell return (lhs->st_size == 0 ? 1 : -1); 2256ff6d951SJohn Birrell 2266ff6d951SJohn Birrell if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != 2276ff6d951SJohn Birrell (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) 2286ff6d951SJohn Birrell return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); 2296ff6d951SJohn Birrell 2306ff6d951SJohn Birrell if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != 2316ff6d951SJohn Birrell (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) 2326ff6d951SJohn Birrell return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); 2336ff6d951SJohn Birrell 2346ff6d951SJohn Birrell return (strcmp(dt_module_strtab + lhs->st_name, 2356ff6d951SJohn Birrell dt_module_strtab + rhs->st_name)); 2366ff6d951SJohn Birrell } 2376ff6d951SJohn Birrell 2386ff6d951SJohn Birrell static void 2396ff6d951SJohn Birrell dt_module_symsort32(dt_module_t *dmp) 2406ff6d951SJohn Birrell { 2416ff6d951SJohn Birrell Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data; 2426ff6d951SJohn Birrell Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap; 2436ff6d951SJohn Birrell const dt_sym_t *dsp = dmp->dm_symchains + 1; 2446ff6d951SJohn Birrell uint_t i, n = dmp->dm_symfree; 2456ff6d951SJohn Birrell 2466ff6d951SJohn Birrell for (i = 1; i < n; i++, dsp++) { 2476ff6d951SJohn Birrell Elf32_Sym *sym = symtab + dsp->ds_symid; 2486ff6d951SJohn Birrell if (sym->st_value != 0 && 2496ff6d951SJohn Birrell (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 2506ff6d951SJohn Birrell *sympp++ = sym; 2516ff6d951SJohn Birrell } 2526ff6d951SJohn Birrell 2536ff6d951SJohn Birrell dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap); 2546ff6d951SJohn Birrell assert(dmp->dm_aslen <= dmp->dm_asrsv); 2556ff6d951SJohn Birrell 2566ff6d951SJohn Birrell dt_module_strtab = dmp->dm_strtab.cts_data; 2576ff6d951SJohn Birrell qsort(dmp->dm_asmap, dmp->dm_aslen, 2586ff6d951SJohn Birrell sizeof (Elf32_Sym *), dt_module_symcomp32); 2596ff6d951SJohn Birrell dt_module_strtab = NULL; 2606ff6d951SJohn Birrell } 2616ff6d951SJohn Birrell 2626ff6d951SJohn Birrell static void 2636ff6d951SJohn Birrell dt_module_symsort64(dt_module_t *dmp) 2646ff6d951SJohn Birrell { 2656ff6d951SJohn Birrell Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data; 2666ff6d951SJohn Birrell Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap; 2676ff6d951SJohn Birrell const dt_sym_t *dsp = dmp->dm_symchains + 1; 2686ff6d951SJohn Birrell uint_t i, n = dmp->dm_symfree; 2696ff6d951SJohn Birrell 2706ff6d951SJohn Birrell for (i = 1; i < n; i++, dsp++) { 2716ff6d951SJohn Birrell Elf64_Sym *sym = symtab + dsp->ds_symid; 2726ff6d951SJohn Birrell if (sym->st_value != 0 && 2736ff6d951SJohn Birrell (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) 2746ff6d951SJohn Birrell *sympp++ = sym; 2756ff6d951SJohn Birrell } 2766ff6d951SJohn Birrell 2776ff6d951SJohn Birrell dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap); 2786ff6d951SJohn Birrell assert(dmp->dm_aslen <= dmp->dm_asrsv); 2796ff6d951SJohn Birrell 2806ff6d951SJohn Birrell dt_module_strtab = dmp->dm_strtab.cts_data; 2816ff6d951SJohn Birrell qsort(dmp->dm_asmap, dmp->dm_aslen, 2826ff6d951SJohn Birrell sizeof (Elf64_Sym *), dt_module_symcomp64); 2836ff6d951SJohn Birrell dt_module_strtab = NULL; 2846ff6d951SJohn Birrell } 2856ff6d951SJohn Birrell 2866ff6d951SJohn Birrell static GElf_Sym * 2876ff6d951SJohn Birrell dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst) 2886ff6d951SJohn Birrell { 2896ff6d951SJohn Birrell if (dst != NULL) { 2906ff6d951SJohn Birrell dst->st_name = src->st_name; 2916ff6d951SJohn Birrell dst->st_info = src->st_info; 2926ff6d951SJohn Birrell dst->st_other = src->st_other; 2936ff6d951SJohn Birrell dst->st_shndx = src->st_shndx; 2946ff6d951SJohn Birrell dst->st_value = src->st_value; 2956ff6d951SJohn Birrell dst->st_size = src->st_size; 2966ff6d951SJohn Birrell } 2976ff6d951SJohn Birrell 2986ff6d951SJohn Birrell return (dst); 2996ff6d951SJohn Birrell } 3006ff6d951SJohn Birrell 3016ff6d951SJohn Birrell static GElf_Sym * 3026ff6d951SJohn Birrell dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst) 3036ff6d951SJohn Birrell { 3046ff6d951SJohn Birrell if (dst != NULL) 3056ff6d951SJohn Birrell bcopy(src, dst, sizeof (GElf_Sym)); 3066ff6d951SJohn Birrell 3076ff6d951SJohn Birrell return (dst); 3086ff6d951SJohn Birrell } 3096ff6d951SJohn Birrell 3106ff6d951SJohn Birrell static GElf_Sym * 3116ff6d951SJohn Birrell dt_module_symname32(dt_module_t *dmp, const char *name, 3126ff6d951SJohn Birrell GElf_Sym *symp, uint_t *idp) 3136ff6d951SJohn Birrell { 3146ff6d951SJohn Birrell const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; 3156ff6d951SJohn Birrell const char *strtab = dmp->dm_strtab.cts_data; 3166ff6d951SJohn Birrell 3176ff6d951SJohn Birrell const Elf32_Sym *sym; 3186ff6d951SJohn Birrell const dt_sym_t *dsp; 3196ff6d951SJohn Birrell uint_t i, h; 3206ff6d951SJohn Birrell 3216ff6d951SJohn Birrell if (dmp->dm_nsymelems == 0) 3226ff6d951SJohn Birrell return (NULL); 3236ff6d951SJohn Birrell 3246ff6d951SJohn Birrell h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 3256ff6d951SJohn Birrell 3266ff6d951SJohn Birrell for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { 3276ff6d951SJohn Birrell dsp = &dmp->dm_symchains[i]; 3286ff6d951SJohn Birrell sym = symtab + dsp->ds_symid; 3296ff6d951SJohn Birrell 3306ff6d951SJohn Birrell if (strcmp(name, strtab + sym->st_name) == 0) { 3316ff6d951SJohn Birrell if (idp != NULL) 3326ff6d951SJohn Birrell *idp = dsp->ds_symid; 3336ff6d951SJohn Birrell return (dt_module_symgelf32(sym, symp)); 3346ff6d951SJohn Birrell } 3356ff6d951SJohn Birrell } 3366ff6d951SJohn Birrell 3376ff6d951SJohn Birrell return (NULL); 3386ff6d951SJohn Birrell } 3396ff6d951SJohn Birrell 3406ff6d951SJohn Birrell static GElf_Sym * 3416ff6d951SJohn Birrell dt_module_symname64(dt_module_t *dmp, const char *name, 3426ff6d951SJohn Birrell GElf_Sym *symp, uint_t *idp) 3436ff6d951SJohn Birrell { 3446ff6d951SJohn Birrell const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; 3456ff6d951SJohn Birrell const char *strtab = dmp->dm_strtab.cts_data; 3466ff6d951SJohn Birrell 3476ff6d951SJohn Birrell const Elf64_Sym *sym; 3486ff6d951SJohn Birrell const dt_sym_t *dsp; 3496ff6d951SJohn Birrell uint_t i, h; 3506ff6d951SJohn Birrell 3516ff6d951SJohn Birrell if (dmp->dm_nsymelems == 0) 3526ff6d951SJohn Birrell return (NULL); 3536ff6d951SJohn Birrell 3546ff6d951SJohn Birrell h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; 3556ff6d951SJohn Birrell 3566ff6d951SJohn Birrell for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { 3576ff6d951SJohn Birrell dsp = &dmp->dm_symchains[i]; 3586ff6d951SJohn Birrell sym = symtab + dsp->ds_symid; 3596ff6d951SJohn Birrell 3606ff6d951SJohn Birrell if (strcmp(name, strtab + sym->st_name) == 0) { 3616ff6d951SJohn Birrell if (idp != NULL) 3626ff6d951SJohn Birrell *idp = dsp->ds_symid; 3636ff6d951SJohn Birrell return (dt_module_symgelf64(sym, symp)); 3646ff6d951SJohn Birrell } 3656ff6d951SJohn Birrell } 3666ff6d951SJohn Birrell 3676ff6d951SJohn Birrell return (NULL); 3686ff6d951SJohn Birrell } 3696ff6d951SJohn Birrell 3706ff6d951SJohn Birrell static GElf_Sym * 3716ff6d951SJohn Birrell dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr, 3726ff6d951SJohn Birrell GElf_Sym *symp, uint_t *idp) 3736ff6d951SJohn Birrell { 3746ff6d951SJohn Birrell const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap; 3756ff6d951SJohn Birrell const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; 3766ff6d951SJohn Birrell const Elf32_Sym *sym; 3776ff6d951SJohn Birrell 3786ff6d951SJohn Birrell uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; 3796ff6d951SJohn Birrell Elf32_Addr v; 3806ff6d951SJohn Birrell 3816ff6d951SJohn Birrell if (dmp->dm_aslen == 0) 3826ff6d951SJohn Birrell return (NULL); 3836ff6d951SJohn Birrell 3846ff6d951SJohn Birrell while (hi - lo > 1) { 3856ff6d951SJohn Birrell mid = (lo + hi) / 2; 3866ff6d951SJohn Birrell if (addr >= asmap[mid]->st_value) 3876ff6d951SJohn Birrell lo = mid; 3886ff6d951SJohn Birrell else 3896ff6d951SJohn Birrell hi = mid; 3906ff6d951SJohn Birrell } 3916ff6d951SJohn Birrell 3926ff6d951SJohn Birrell i = addr < asmap[hi]->st_value ? lo : hi; 3936ff6d951SJohn Birrell sym = asmap[i]; 3946ff6d951SJohn Birrell v = sym->st_value; 3956ff6d951SJohn Birrell 3966ff6d951SJohn Birrell /* 3976ff6d951SJohn Birrell * If the previous entry has the same value, improve our choice. The 3986ff6d951SJohn Birrell * order of equal-valued symbols is determined by the comparison func. 3996ff6d951SJohn Birrell */ 4006ff6d951SJohn Birrell while (i-- != 0 && asmap[i]->st_value == v) 4016ff6d951SJohn Birrell sym = asmap[i]; 4026ff6d951SJohn Birrell 4036ff6d951SJohn Birrell if (addr - sym->st_value < MAX(sym->st_size, 1)) { 4046ff6d951SJohn Birrell if (idp != NULL) 4056ff6d951SJohn Birrell *idp = (uint_t)(sym - symtab); 4066ff6d951SJohn Birrell return (dt_module_symgelf32(sym, symp)); 4076ff6d951SJohn Birrell } 4086ff6d951SJohn Birrell 4096ff6d951SJohn Birrell return (NULL); 4106ff6d951SJohn Birrell } 4116ff6d951SJohn Birrell 4126ff6d951SJohn Birrell static GElf_Sym * 4136ff6d951SJohn Birrell dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr, 4146ff6d951SJohn Birrell GElf_Sym *symp, uint_t *idp) 4156ff6d951SJohn Birrell { 4166ff6d951SJohn Birrell const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap; 4176ff6d951SJohn Birrell const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; 4186ff6d951SJohn Birrell const Elf64_Sym *sym; 4196ff6d951SJohn Birrell 4206ff6d951SJohn Birrell uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; 4216ff6d951SJohn Birrell Elf64_Addr v; 4226ff6d951SJohn Birrell 4236ff6d951SJohn Birrell if (dmp->dm_aslen == 0) 4246ff6d951SJohn Birrell return (NULL); 4256ff6d951SJohn Birrell 4266ff6d951SJohn Birrell while (hi - lo > 1) { 4276ff6d951SJohn Birrell mid = (lo + hi) / 2; 4286ff6d951SJohn Birrell if (addr >= asmap[mid]->st_value) 4296ff6d951SJohn Birrell lo = mid; 4306ff6d951SJohn Birrell else 4316ff6d951SJohn Birrell hi = mid; 4326ff6d951SJohn Birrell } 4336ff6d951SJohn Birrell 4346ff6d951SJohn Birrell i = addr < asmap[hi]->st_value ? lo : hi; 4356ff6d951SJohn Birrell sym = asmap[i]; 4366ff6d951SJohn Birrell v = sym->st_value; 4376ff6d951SJohn Birrell 4386ff6d951SJohn Birrell /* 4396ff6d951SJohn Birrell * If the previous entry has the same value, improve our choice. The 4406ff6d951SJohn Birrell * order of equal-valued symbols is determined by the comparison func. 4416ff6d951SJohn Birrell */ 4426ff6d951SJohn Birrell while (i-- != 0 && asmap[i]->st_value == v) 4436ff6d951SJohn Birrell sym = asmap[i]; 4446ff6d951SJohn Birrell 4456ff6d951SJohn Birrell if (addr - sym->st_value < MAX(sym->st_size, 1)) { 4466ff6d951SJohn Birrell if (idp != NULL) 4476ff6d951SJohn Birrell *idp = (uint_t)(sym - symtab); 4486ff6d951SJohn Birrell return (dt_module_symgelf64(sym, symp)); 4496ff6d951SJohn Birrell } 4506ff6d951SJohn Birrell 4516ff6d951SJohn Birrell return (NULL); 4526ff6d951SJohn Birrell } 4536ff6d951SJohn Birrell 4546ff6d951SJohn Birrell static const dt_modops_t dt_modops_32 = { 455f6372351SMark Johnston .do_syminit = dt_module_syminit32, 456f6372351SMark Johnston .do_symsort = dt_module_symsort32, 457f6372351SMark Johnston .do_symname = dt_module_symname32, 458f6372351SMark Johnston .do_symaddr = dt_module_symaddr32 4596ff6d951SJohn Birrell }; 4606ff6d951SJohn Birrell 4616ff6d951SJohn Birrell static const dt_modops_t dt_modops_64 = { 462f6372351SMark Johnston .do_syminit = dt_module_syminit64, 463f6372351SMark Johnston .do_symsort = dt_module_symsort64, 464f6372351SMark Johnston .do_symname = dt_module_symname64, 465f6372351SMark Johnston .do_symaddr = dt_module_symaddr64 4666ff6d951SJohn Birrell }; 4676ff6d951SJohn Birrell 4686ff6d951SJohn Birrell dt_module_t * 4696ff6d951SJohn Birrell dt_module_create(dtrace_hdl_t *dtp, const char *name) 4706ff6d951SJohn Birrell { 4718e648814SRui Paulo long pid; 4728e648814SRui Paulo char *eptr; 4738e648814SRui Paulo dt_ident_t *idp; 4746ff6d951SJohn Birrell uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; 4756ff6d951SJohn Birrell dt_module_t *dmp; 4766ff6d951SJohn Birrell 4776ff6d951SJohn Birrell for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { 4786ff6d951SJohn Birrell if (strcmp(dmp->dm_name, name) == 0) 4796ff6d951SJohn Birrell return (dmp); 4806ff6d951SJohn Birrell } 4816ff6d951SJohn Birrell 4826ff6d951SJohn Birrell if ((dmp = malloc(sizeof (dt_module_t))) == NULL) 4836ff6d951SJohn Birrell return (NULL); /* caller must handle allocation failure */ 4846ff6d951SJohn Birrell 4856ff6d951SJohn Birrell bzero(dmp, sizeof (dt_module_t)); 4866ff6d951SJohn Birrell (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); 4876ff6d951SJohn Birrell dt_list_append(&dtp->dt_modlist, dmp); 4886ff6d951SJohn Birrell dmp->dm_next = dtp->dt_mods[h]; 4896ff6d951SJohn Birrell dtp->dt_mods[h] = dmp; 4906ff6d951SJohn Birrell dtp->dt_nmods++; 4916ff6d951SJohn Birrell 4926ff6d951SJohn Birrell if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) 4936ff6d951SJohn Birrell dmp->dm_ops = &dt_modops_64; 4946ff6d951SJohn Birrell else 4956ff6d951SJohn Birrell dmp->dm_ops = &dt_modops_32; 4966ff6d951SJohn Birrell 4978e648814SRui Paulo /* 4988e648814SRui Paulo * Modules for userland processes are special. They always refer to a 4998e648814SRui Paulo * specific process and have a copy of their CTF data from a specific 5008e648814SRui Paulo * instant in time. Any dt_module_t that begins with 'pid' is a module 5018e648814SRui Paulo * for a specific process, much like how any probe description that 5028e648814SRui Paulo * begins with 'pid' is special. pid123 refers to process 123. A module 5038e648814SRui Paulo * that is just 'pid' refers specifically to pid$target. This is 5048e648814SRui Paulo * generally done as D does not currently allow for macros to be 5058e648814SRui Paulo * evaluated when working with types. 5068e648814SRui Paulo */ 5078e648814SRui Paulo if (strncmp(dmp->dm_name, "pid", 3) == 0) { 5088e648814SRui Paulo errno = 0; 5098e648814SRui Paulo if (dmp->dm_name[3] == '\0') { 5108e648814SRui Paulo idp = dt_idhash_lookup(dtp->dt_macros, "target"); 5118e648814SRui Paulo if (idp != NULL && idp->di_id != 0) 5128e648814SRui Paulo dmp->dm_pid = idp->di_id; 5138e648814SRui Paulo } else { 5148e648814SRui Paulo pid = strtol(dmp->dm_name + 3, &eptr, 10); 5158e648814SRui Paulo if (errno == 0 && *eptr == '\0') 5168e648814SRui Paulo dmp->dm_pid = (pid_t)pid; 5178e648814SRui Paulo else 5188e648814SRui Paulo dt_dprintf("encountered malformed pid " 5198e648814SRui Paulo "module: %s\n", dmp->dm_name); 5208e648814SRui Paulo } 5218e648814SRui Paulo } 5228e648814SRui Paulo 5236ff6d951SJohn Birrell return (dmp); 5246ff6d951SJohn Birrell } 5256ff6d951SJohn Birrell 5266ff6d951SJohn Birrell dt_module_t * 5276ff6d951SJohn Birrell dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name) 5286ff6d951SJohn Birrell { 5296ff6d951SJohn Birrell uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; 5306ff6d951SJohn Birrell dt_module_t *dmp; 5316ff6d951SJohn Birrell 5326ff6d951SJohn Birrell for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { 5336ff6d951SJohn Birrell if (strcmp(dmp->dm_name, name) == 0) 5346ff6d951SJohn Birrell return (dmp); 5356ff6d951SJohn Birrell } 5366ff6d951SJohn Birrell 5376ff6d951SJohn Birrell return (NULL); 5386ff6d951SJohn Birrell } 5396ff6d951SJohn Birrell 5406ff6d951SJohn Birrell /*ARGSUSED*/ 5416ff6d951SJohn Birrell dt_module_t * 5426ff6d951SJohn Birrell dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp) 5436ff6d951SJohn Birrell { 5446ff6d951SJohn Birrell return (ctfp ? ctf_getspecific(ctfp) : NULL); 5456ff6d951SJohn Birrell } 5466ff6d951SJohn Birrell 5478436cb81SMark Johnston #ifdef __FreeBSD__ 5488436cb81SMark Johnston dt_kmodule_t * 5498436cb81SMark Johnston dt_kmodule_lookup(dtrace_hdl_t *dtp, const char *name) 5508436cb81SMark Johnston { 5518436cb81SMark Johnston uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; 5528436cb81SMark Johnston dt_kmodule_t *dkmp; 5538436cb81SMark Johnston 5548436cb81SMark Johnston for (dkmp = dtp->dt_kmods[h]; dkmp != NULL; dkmp = dkmp->dkm_next) { 5558436cb81SMark Johnston if (strcmp(dkmp->dkm_name, name) == 0) 5568436cb81SMark Johnston return (dkmp); 5578436cb81SMark Johnston } 5588436cb81SMark Johnston 5598436cb81SMark Johnston return (NULL); 5608436cb81SMark Johnston } 5618436cb81SMark Johnston #endif 5628436cb81SMark Johnston 5636ff6d951SJohn Birrell static int 5646ff6d951SJohn Birrell dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp) 5656ff6d951SJohn Birrell { 5666ff6d951SJohn Birrell const char *s; 5676ff6d951SJohn Birrell size_t shstrs; 5686ff6d951SJohn Birrell GElf_Shdr sh; 5696ff6d951SJohn Birrell Elf_Data *dp; 5706ff6d951SJohn Birrell Elf_Scn *sp; 5716ff6d951SJohn Birrell 5721670a1c2SRui Paulo if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) 5736ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOTLOADED)); 5746ff6d951SJohn Birrell 5756ff6d951SJohn Birrell for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { 5766ff6d951SJohn Birrell if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || 5776ff6d951SJohn Birrell (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) 5786ff6d951SJohn Birrell continue; /* skip any malformed sections */ 5796ff6d951SJohn Birrell 5806ff6d951SJohn Birrell if (sh.sh_type == ctsp->cts_type && 5816ff6d951SJohn Birrell sh.sh_entsize == ctsp->cts_entsize && 5826ff6d951SJohn Birrell strcmp(s, ctsp->cts_name) == 0) 5836ff6d951SJohn Birrell break; /* section matches specification */ 5846ff6d951SJohn Birrell } 5856ff6d951SJohn Birrell 5866ff6d951SJohn Birrell /* 5876ff6d951SJohn Birrell * If the section isn't found, return success but leave cts_data set 5886ff6d951SJohn Birrell * to NULL and cts_size set to zero for our caller. 5896ff6d951SJohn Birrell */ 5906ff6d951SJohn Birrell if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL) 5916ff6d951SJohn Birrell return (0); 5926ff6d951SJohn Birrell 593bc96366cSSteven Hartland #ifdef illumos 5946ff6d951SJohn Birrell ctsp->cts_data = dp->d_buf; 595f1e56186SJohn Birrell #else 596f1e56186SJohn Birrell if ((ctsp->cts_data = malloc(dp->d_size)) == NULL) 597f1e56186SJohn Birrell return (0); 598f1e56186SJohn Birrell memcpy(ctsp->cts_data, dp->d_buf, dp->d_size); 599f1e56186SJohn Birrell #endif 6006ff6d951SJohn Birrell ctsp->cts_size = dp->d_size; 6016ff6d951SJohn Birrell 6026ff6d951SJohn Birrell dt_dprintf("loaded %s [%s] (%lu bytes)\n", 6036ff6d951SJohn Birrell dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size); 6046ff6d951SJohn Birrell 6056ff6d951SJohn Birrell return (0); 6066ff6d951SJohn Birrell } 6076ff6d951SJohn Birrell 6088e648814SRui Paulo typedef struct dt_module_cb_arg { 6098e648814SRui Paulo struct ps_prochandle *dpa_proc; 6108e648814SRui Paulo dtrace_hdl_t *dpa_dtp; 6118e648814SRui Paulo dt_module_t *dpa_dmp; 6128e648814SRui Paulo uint_t dpa_count; 6138e648814SRui Paulo } dt_module_cb_arg_t; 6148e648814SRui Paulo 6158e648814SRui Paulo /* ARGSUSED */ 6168e648814SRui Paulo static int 6178e648814SRui Paulo dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj) 6188e648814SRui Paulo { 6198e648814SRui Paulo ctf_file_t *fp; 6208e648814SRui Paulo dt_module_cb_arg_t *dcp = arg; 6218e648814SRui Paulo 6228e648814SRui Paulo /* Try to grab a ctf container if it exists */ 6238e648814SRui Paulo fp = Pname_to_ctf(dcp->dpa_proc, obj); 6248e648814SRui Paulo if (fp != NULL) 6258e648814SRui Paulo dcp->dpa_count++; 6268e648814SRui Paulo return (0); 6278e648814SRui Paulo } 6288e648814SRui Paulo 6298e648814SRui Paulo /* ARGSUSED */ 6308e648814SRui Paulo static int 6318e648814SRui Paulo dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj) 6328e648814SRui Paulo { 6338e648814SRui Paulo ctf_file_t *fp; 6348e648814SRui Paulo char buf[MAXPATHLEN], *p; 6358e648814SRui Paulo dt_module_cb_arg_t *dcp = arg; 6368e648814SRui Paulo int count = dcp->dpa_count; 6378e648814SRui Paulo Lmid_t lmid; 6388e648814SRui Paulo 6398e648814SRui Paulo fp = Pname_to_ctf(dcp->dpa_proc, obj); 6408e648814SRui Paulo if (fp == NULL) 6418e648814SRui Paulo return (0); 6428e648814SRui Paulo fp = ctf_dup(fp); 6438e648814SRui Paulo if (fp == NULL) 6448e648814SRui Paulo return (0); 6458e648814SRui Paulo dcp->dpa_dmp->dm_libctfp[count] = fp; 6468e648814SRui Paulo /* 6478e648814SRui Paulo * While it'd be nice to simply use objname here, because of our prior 6488e648814SRui Paulo * actions we'll always get a resolved object name to its on disk file. 6498e648814SRui Paulo * Like the pid provider, we need to tell a bit of a lie here. The type 6508e648814SRui Paulo * that the user thinks of is in terms of the libraries they requested, 6518e648814SRui Paulo * eg. libc.so.1, they don't care about the fact that it's 6528e648814SRui Paulo * libc_hwcap.so.1. 6538e648814SRui Paulo */ 6548e648814SRui Paulo (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf)); 6558e648814SRui Paulo if ((p = strrchr(buf, '/')) == NULL) 6568e648814SRui Paulo p = buf; 6578e648814SRui Paulo else 6588e648814SRui Paulo p++; 6598e648814SRui Paulo 6608e648814SRui Paulo /* 6618e648814SRui Paulo * If for some reason we can't find a link map id for this module, which 6628e648814SRui Paulo * would be really quite weird. We instead just say the link map id is 6638e648814SRui Paulo * zero. 6648e648814SRui Paulo */ 6658e648814SRui Paulo if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0) 6668e648814SRui Paulo lmid = 0; 6678e648814SRui Paulo 6688e648814SRui Paulo if (lmid == 0) 6698e648814SRui Paulo dcp->dpa_dmp->dm_libctfn[count] = strdup(p); 6708e648814SRui Paulo else 6718e648814SRui Paulo (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count], 6728e648814SRui Paulo "LM%x`%s", lmid, p); 6738e648814SRui Paulo if (dcp->dpa_dmp->dm_libctfn[count] == NULL) 6748e648814SRui Paulo return (1); 6758e648814SRui Paulo ctf_setspecific(fp, dcp->dpa_dmp); 6768e648814SRui Paulo dcp->dpa_count++; 6778e648814SRui Paulo return (0); 6788e648814SRui Paulo } 6798e648814SRui Paulo 6808e648814SRui Paulo /* 6818e648814SRui Paulo * We've been asked to load data that belongs to another process. As such we're 6828e648814SRui Paulo * going to pgrab it at this instant, load everything that we might ever care 6838e648814SRui Paulo * about, and then drive on. The reason for this is that the process that we're 6848e648814SRui Paulo * interested in might be changing. As long as we have grabbed it, then this 6858e648814SRui Paulo * can't be a problem for us. 6868e648814SRui Paulo * 6878e648814SRui Paulo * For now, we're actually going to punt on most things and just try to get CTF 6888e648814SRui Paulo * data, nothing else. Basically this is only useful as a source of type 6898e648814SRui Paulo * information, we can't go and do the stacktrace lookups, etc. 6908e648814SRui Paulo */ 6918e648814SRui Paulo static int 6928e648814SRui Paulo dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp) 6938e648814SRui Paulo { 6948e648814SRui Paulo struct ps_prochandle *p; 6958e648814SRui Paulo dt_module_cb_arg_t arg; 6968e648814SRui Paulo 6978e648814SRui Paulo /* 6988e648814SRui Paulo * Note that on success we do not release this hold. We must hold this 6998e648814SRui Paulo * for our life time. 7008e648814SRui Paulo */ 7018e648814SRui Paulo p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE); 7028e648814SRui Paulo if (p == NULL) { 7038e648814SRui Paulo dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid); 7048e648814SRui Paulo return (dt_set_errno(dtp, EDT_CANTLOAD)); 7058e648814SRui Paulo } 7068e648814SRui Paulo dt_proc_lock(dtp, p); 7078e648814SRui Paulo 7088e648814SRui Paulo arg.dpa_proc = p; 7098e648814SRui Paulo arg.dpa_dtp = dtp; 7108e648814SRui Paulo arg.dpa_dmp = dmp; 7118e648814SRui Paulo arg.dpa_count = 0; 7128e648814SRui Paulo if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) { 7138e648814SRui Paulo dt_dprintf("failed to iterate objects\n"); 714f7d5087aSMark Johnston dt_proc_unlock(dtp, p); 7158e648814SRui Paulo dt_proc_release(dtp, p); 7168e648814SRui Paulo return (dt_set_errno(dtp, EDT_CANTLOAD)); 7178e648814SRui Paulo } 7188e648814SRui Paulo 7198e648814SRui Paulo if (arg.dpa_count == 0) { 7208e648814SRui Paulo dt_dprintf("no ctf data present\n"); 7218e648814SRui Paulo dt_proc_unlock(dtp, p); 7228e648814SRui Paulo dt_proc_release(dtp, p); 7238e648814SRui Paulo return (dt_set_errno(dtp, EDT_CANTLOAD)); 7248e648814SRui Paulo } 7258e648814SRui Paulo 726273df429SPedro F. Giffuni dmp->dm_libctfp = calloc(arg.dpa_count, sizeof (ctf_file_t *)); 7278e648814SRui Paulo if (dmp->dm_libctfp == NULL) { 7288e648814SRui Paulo dt_proc_unlock(dtp, p); 7298e648814SRui Paulo dt_proc_release(dtp, p); 7308e648814SRui Paulo return (dt_set_errno(dtp, EDT_NOMEM)); 7318e648814SRui Paulo } 7328e648814SRui Paulo 733273df429SPedro F. Giffuni dmp->dm_libctfn = calloc(arg.dpa_count, sizeof (char *)); 7348e648814SRui Paulo if (dmp->dm_libctfn == NULL) { 7358e648814SRui Paulo free(dmp->dm_libctfp); 7368e648814SRui Paulo dt_proc_unlock(dtp, p); 7378e648814SRui Paulo dt_proc_release(dtp, p); 7388e648814SRui Paulo return (dt_set_errno(dtp, EDT_NOMEM)); 7398e648814SRui Paulo } 7408e648814SRui Paulo 7418e648814SRui Paulo dmp->dm_nctflibs = arg.dpa_count; 7428e648814SRui Paulo 7438e648814SRui Paulo arg.dpa_count = 0; 7448e648814SRui Paulo if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) { 7458e648814SRui Paulo dt_proc_unlock(dtp, p); 7468e648814SRui Paulo dt_module_unload(dtp, dmp); 7478e648814SRui Paulo dt_proc_release(dtp, p); 7488e648814SRui Paulo return (dt_set_errno(dtp, EDT_CANTLOAD)); 7498e648814SRui Paulo } 7508e648814SRui Paulo assert(arg.dpa_count == dmp->dm_nctflibs); 7518e648814SRui Paulo dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count, 7528e648814SRui Paulo (int)dmp->dm_pid); 7538e648814SRui Paulo 7548e648814SRui Paulo dt_proc_unlock(dtp, p); 7558e648814SRui Paulo dt_proc_release(dtp, p); 7568e648814SRui Paulo dmp->dm_flags |= DT_DM_LOADED; 7578e648814SRui Paulo 7588e648814SRui Paulo return (0); 7598e648814SRui Paulo } 7608e648814SRui Paulo 7616ff6d951SJohn Birrell int 7626ff6d951SJohn Birrell dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) 7636ff6d951SJohn Birrell { 7646ff6d951SJohn Birrell if (dmp->dm_flags & DT_DM_LOADED) 7656ff6d951SJohn Birrell return (0); /* module is already loaded */ 7666ff6d951SJohn Birrell 7678e648814SRui Paulo if (dmp->dm_pid != 0) 7688e648814SRui Paulo return (dt_module_load_proc(dtp, dmp)); 7698e648814SRui Paulo 7706ff6d951SJohn Birrell dmp->dm_ctdata.cts_name = ".SUNW_ctf"; 7716ff6d951SJohn Birrell dmp->dm_ctdata.cts_type = SHT_PROGBITS; 7726ff6d951SJohn Birrell dmp->dm_ctdata.cts_flags = 0; 7736ff6d951SJohn Birrell dmp->dm_ctdata.cts_data = NULL; 7746ff6d951SJohn Birrell dmp->dm_ctdata.cts_size = 0; 7756ff6d951SJohn Birrell dmp->dm_ctdata.cts_entsize = 0; 7766ff6d951SJohn Birrell dmp->dm_ctdata.cts_offset = 0; 7776ff6d951SJohn Birrell 7786ff6d951SJohn Birrell dmp->dm_symtab.cts_name = ".symtab"; 7796ff6d951SJohn Birrell dmp->dm_symtab.cts_type = SHT_SYMTAB; 7806ff6d951SJohn Birrell dmp->dm_symtab.cts_flags = 0; 7816ff6d951SJohn Birrell dmp->dm_symtab.cts_data = NULL; 7826ff6d951SJohn Birrell dmp->dm_symtab.cts_size = 0; 7836ff6d951SJohn Birrell dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ? 7846ff6d951SJohn Birrell sizeof (Elf64_Sym) : sizeof (Elf32_Sym); 7856ff6d951SJohn Birrell dmp->dm_symtab.cts_offset = 0; 7866ff6d951SJohn Birrell 7876ff6d951SJohn Birrell dmp->dm_strtab.cts_name = ".strtab"; 7886ff6d951SJohn Birrell dmp->dm_strtab.cts_type = SHT_STRTAB; 7896ff6d951SJohn Birrell dmp->dm_strtab.cts_flags = 0; 7906ff6d951SJohn Birrell dmp->dm_strtab.cts_data = NULL; 7916ff6d951SJohn Birrell dmp->dm_strtab.cts_size = 0; 7926ff6d951SJohn Birrell dmp->dm_strtab.cts_entsize = 0; 7936ff6d951SJohn Birrell dmp->dm_strtab.cts_offset = 0; 7946ff6d951SJohn Birrell 7956ff6d951SJohn Birrell /* 7966ff6d951SJohn Birrell * Attempt to load the module's CTF section, symbol table section, and 7976ff6d951SJohn Birrell * string table section. Note that modules may not contain CTF data: 7986ff6d951SJohn Birrell * this will result in a successful load_sect but data of size zero. 7996ff6d951SJohn Birrell * We will then fail if dt_module_getctf() is called, as shown below. 8006ff6d951SJohn Birrell */ 8016ff6d951SJohn Birrell if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 || 8026ff6d951SJohn Birrell dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 || 8036ff6d951SJohn Birrell dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) { 8046ff6d951SJohn Birrell dt_module_unload(dtp, dmp); 8056ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 8066ff6d951SJohn Birrell } 8076ff6d951SJohn Birrell 8086ff6d951SJohn Birrell /* 8096ff6d951SJohn Birrell * Allocate the hash chains and hash buckets for symbol name lookup. 8106ff6d951SJohn Birrell * This is relatively simple since the symbol table is of fixed size 8116ff6d951SJohn Birrell * and is known in advance. We allocate one extra element since we 8126ff6d951SJohn Birrell * use element indices instead of pointers and zero is our sentinel. 8136ff6d951SJohn Birrell */ 8146ff6d951SJohn Birrell dmp->dm_nsymelems = 8156ff6d951SJohn Birrell dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize; 8166ff6d951SJohn Birrell 8176ff6d951SJohn Birrell dmp->dm_nsymbuckets = _dtrace_strbuckets; 8186ff6d951SJohn Birrell dmp->dm_symfree = 1; /* first free element is index 1 */ 8196ff6d951SJohn Birrell 820273df429SPedro F. Giffuni dmp->dm_symbuckets = calloc(dmp->dm_nsymbuckets, sizeof (uint_t)); 821273df429SPedro F. Giffuni dmp->dm_symchains = calloc(dmp->dm_nsymelems + 1, sizeof (dt_sym_t)); 8226ff6d951SJohn Birrell 8236ff6d951SJohn Birrell if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) { 8246ff6d951SJohn Birrell dt_module_unload(dtp, dmp); 8256ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 8266ff6d951SJohn Birrell } 8276ff6d951SJohn Birrell 8286ff6d951SJohn Birrell /* 8296ff6d951SJohn Birrell * Iterate over the symbol table data buffer and insert each symbol 8306ff6d951SJohn Birrell * name into the name hash if the name and type are valid. Then 8316ff6d951SJohn Birrell * allocate the address map, fill it in, and sort it. 8326ff6d951SJohn Birrell */ 8336ff6d951SJohn Birrell dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp); 8346ff6d951SJohn Birrell 8356ff6d951SJohn Birrell dt_dprintf("hashed %s [%s] (%u symbols)\n", 8366ff6d951SJohn Birrell dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1); 8376ff6d951SJohn Birrell 8386ff6d951SJohn Birrell if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) { 8396ff6d951SJohn Birrell dt_module_unload(dtp, dmp); 8406ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 8416ff6d951SJohn Birrell } 8426ff6d951SJohn Birrell 8436ff6d951SJohn Birrell dmp->dm_ops->do_symsort(dmp); 8446ff6d951SJohn Birrell 8456ff6d951SJohn Birrell dt_dprintf("sorted %s [%s] (%u symbols)\n", 8466ff6d951SJohn Birrell dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen); 8476ff6d951SJohn Birrell 8486ff6d951SJohn Birrell dmp->dm_flags |= DT_DM_LOADED; 8496ff6d951SJohn Birrell return (0); 8506ff6d951SJohn Birrell } 8516ff6d951SJohn Birrell 8528e648814SRui Paulo int 8538e648814SRui Paulo dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp) 8548e648814SRui Paulo { 8558e648814SRui Paulo if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0) 8568e648814SRui Paulo return (1); 8578e648814SRui Paulo return (dt_module_getctf(dtp, dmp) != NULL); 8588e648814SRui Paulo } 8598e648814SRui Paulo 8606ff6d951SJohn Birrell ctf_file_t * 8616ff6d951SJohn Birrell dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp) 8626ff6d951SJohn Birrell { 8636ff6d951SJohn Birrell const char *parent; 8646ff6d951SJohn Birrell dt_module_t *pmp; 8656ff6d951SJohn Birrell ctf_file_t *pfp; 8666ff6d951SJohn Birrell int model; 8676ff6d951SJohn Birrell 8686ff6d951SJohn Birrell if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0) 8696ff6d951SJohn Birrell return (dmp->dm_ctfp); 8706ff6d951SJohn Birrell 8716ff6d951SJohn Birrell if (dmp->dm_ops == &dt_modops_64) 8726ff6d951SJohn Birrell model = CTF_MODEL_LP64; 8736ff6d951SJohn Birrell else 8746ff6d951SJohn Birrell model = CTF_MODEL_ILP32; 8756ff6d951SJohn Birrell 8766ff6d951SJohn Birrell /* 8776ff6d951SJohn Birrell * If the data model of the module does not match our program data 8786ff6d951SJohn Birrell * model, then do not permit CTF from this module to be opened and 8796ff6d951SJohn Birrell * returned to the compiler. If we support mixed data models in the 8806ff6d951SJohn Birrell * future for combined kernel/user tracing, this can be removed. 8816ff6d951SJohn Birrell */ 8826ff6d951SJohn Birrell if (dtp->dt_conf.dtc_ctfmodel != model) { 8836ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_DATAMODEL); 8846ff6d951SJohn Birrell return (NULL); 8856ff6d951SJohn Birrell } 8866ff6d951SJohn Birrell 8876ff6d951SJohn Birrell if (dmp->dm_ctdata.cts_size == 0) { 8886ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOCTF); 8896ff6d951SJohn Birrell return (NULL); 8906ff6d951SJohn Birrell } 8916ff6d951SJohn Birrell 8926ff6d951SJohn Birrell dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata, 8936ff6d951SJohn Birrell &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr); 8946ff6d951SJohn Birrell 8956ff6d951SJohn Birrell if (dmp->dm_ctfp == NULL) { 8966ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_CTF); 8976ff6d951SJohn Birrell return (NULL); 8986ff6d951SJohn Birrell } 8996ff6d951SJohn Birrell 9006ff6d951SJohn Birrell (void) ctf_setmodel(dmp->dm_ctfp, model); 9016ff6d951SJohn Birrell ctf_setspecific(dmp->dm_ctfp, dmp); 9026ff6d951SJohn Birrell 9036ff6d951SJohn Birrell if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) { 9046ff6d951SJohn Birrell if ((pmp = dt_module_create(dtp, parent)) == NULL || 9056ff6d951SJohn Birrell (pfp = dt_module_getctf(dtp, pmp)) == NULL) { 9066ff6d951SJohn Birrell if (pmp == NULL) 9076ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM); 9086ff6d951SJohn Birrell goto err; 9096ff6d951SJohn Birrell } 9106ff6d951SJohn Birrell 9116ff6d951SJohn Birrell if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) { 9126ff6d951SJohn Birrell dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp); 9136ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_CTF); 9146ff6d951SJohn Birrell goto err; 9156ff6d951SJohn Birrell } 9166ff6d951SJohn Birrell } 9176ff6d951SJohn Birrell 9186ff6d951SJohn Birrell dt_dprintf("loaded CTF container for %s (%p)\n", 9196ff6d951SJohn Birrell dmp->dm_name, (void *)dmp->dm_ctfp); 9206ff6d951SJohn Birrell 9216ff6d951SJohn Birrell return (dmp->dm_ctfp); 9226ff6d951SJohn Birrell 9236ff6d951SJohn Birrell err: 9246ff6d951SJohn Birrell ctf_close(dmp->dm_ctfp); 9256ff6d951SJohn Birrell dmp->dm_ctfp = NULL; 9266ff6d951SJohn Birrell return (NULL); 9276ff6d951SJohn Birrell } 9286ff6d951SJohn Birrell 9296ff6d951SJohn Birrell /*ARGSUSED*/ 9306ff6d951SJohn Birrell void 9316ff6d951SJohn Birrell dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) 9326ff6d951SJohn Birrell { 9338e648814SRui Paulo int i; 9348e648814SRui Paulo 9356ff6d951SJohn Birrell ctf_close(dmp->dm_ctfp); 9366ff6d951SJohn Birrell dmp->dm_ctfp = NULL; 9376ff6d951SJohn Birrell 938bc96366cSSteven Hartland #ifndef illumos 939f1e56186SJohn Birrell if (dmp->dm_ctdata.cts_data != NULL) { 940f1e56186SJohn Birrell free(dmp->dm_ctdata.cts_data); 941f1e56186SJohn Birrell } 942f1e56186SJohn Birrell if (dmp->dm_symtab.cts_data != NULL) { 943f1e56186SJohn Birrell free(dmp->dm_symtab.cts_data); 944f1e56186SJohn Birrell } 945f1e56186SJohn Birrell if (dmp->dm_strtab.cts_data != NULL) { 946f1e56186SJohn Birrell free(dmp->dm_strtab.cts_data); 947f1e56186SJohn Birrell } 948f1e56186SJohn Birrell #endif 949f1e56186SJohn Birrell 9508e648814SRui Paulo if (dmp->dm_libctfp != NULL) { 9518e648814SRui Paulo for (i = 0; i < dmp->dm_nctflibs; i++) { 9528e648814SRui Paulo ctf_close(dmp->dm_libctfp[i]); 9538e648814SRui Paulo free(dmp->dm_libctfn[i]); 9548e648814SRui Paulo } 9558e648814SRui Paulo free(dmp->dm_libctfp); 9568e648814SRui Paulo free(dmp->dm_libctfn); 9578e648814SRui Paulo dmp->dm_libctfp = NULL; 9588e648814SRui Paulo dmp->dm_nctflibs = 0; 9598e648814SRui Paulo } 9608e648814SRui Paulo 9616ff6d951SJohn Birrell bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); 9626ff6d951SJohn Birrell bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); 9636ff6d951SJohn Birrell bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); 9646ff6d951SJohn Birrell 9656ff6d951SJohn Birrell if (dmp->dm_symbuckets != NULL) { 9666ff6d951SJohn Birrell free(dmp->dm_symbuckets); 9676ff6d951SJohn Birrell dmp->dm_symbuckets = NULL; 9686ff6d951SJohn Birrell } 9696ff6d951SJohn Birrell 9706ff6d951SJohn Birrell if (dmp->dm_symchains != NULL) { 9716ff6d951SJohn Birrell free(dmp->dm_symchains); 9726ff6d951SJohn Birrell dmp->dm_symchains = NULL; 9736ff6d951SJohn Birrell } 9746ff6d951SJohn Birrell 9756ff6d951SJohn Birrell if (dmp->dm_asmap != NULL) { 9766ff6d951SJohn Birrell free(dmp->dm_asmap); 9776ff6d951SJohn Birrell dmp->dm_asmap = NULL; 9786ff6d951SJohn Birrell } 979556cb98dSAndriy Gapon #if defined(__FreeBSD__) 980556cb98dSAndriy Gapon if (dmp->dm_sec_offsets != NULL) { 981556cb98dSAndriy Gapon free(dmp->dm_sec_offsets); 982556cb98dSAndriy Gapon dmp->dm_sec_offsets = NULL; 983556cb98dSAndriy Gapon } 984556cb98dSAndriy Gapon #endif 9856ff6d951SJohn Birrell dmp->dm_symfree = 0; 9866ff6d951SJohn Birrell dmp->dm_nsymbuckets = 0; 9876ff6d951SJohn Birrell dmp->dm_nsymelems = 0; 9886ff6d951SJohn Birrell dmp->dm_asrsv = 0; 9896ff6d951SJohn Birrell dmp->dm_aslen = 0; 9906ff6d951SJohn Birrell 991f1e56186SJohn Birrell dmp->dm_text_va = 0; 9926ff6d951SJohn Birrell dmp->dm_text_size = 0; 993f1e56186SJohn Birrell dmp->dm_data_va = 0; 9946ff6d951SJohn Birrell dmp->dm_data_size = 0; 995f1e56186SJohn Birrell dmp->dm_bss_va = 0; 9966ff6d951SJohn Birrell dmp->dm_bss_size = 0; 9976ff6d951SJohn Birrell 9986ff6d951SJohn Birrell if (dmp->dm_extern != NULL) { 9996ff6d951SJohn Birrell dt_idhash_destroy(dmp->dm_extern); 10006ff6d951SJohn Birrell dmp->dm_extern = NULL; 10016ff6d951SJohn Birrell } 10026ff6d951SJohn Birrell 10036ff6d951SJohn Birrell (void) elf_end(dmp->dm_elf); 10046ff6d951SJohn Birrell dmp->dm_elf = NULL; 10056ff6d951SJohn Birrell 10068e648814SRui Paulo dmp->dm_pid = 0; 10078e648814SRui Paulo 10086ff6d951SJohn Birrell dmp->dm_flags &= ~DT_DM_LOADED; 10096ff6d951SJohn Birrell } 10106ff6d951SJohn Birrell 10116ff6d951SJohn Birrell void 10126ff6d951SJohn Birrell dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp) 10136ff6d951SJohn Birrell { 10141670a1c2SRui Paulo uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets; 10151670a1c2SRui Paulo dt_module_t **dmpp = &dtp->dt_mods[h]; 10161670a1c2SRui Paulo 10176ff6d951SJohn Birrell dt_list_delete(&dtp->dt_modlist, dmp); 10186ff6d951SJohn Birrell assert(dtp->dt_nmods != 0); 10196ff6d951SJohn Birrell dtp->dt_nmods--; 10206ff6d951SJohn Birrell 10211670a1c2SRui Paulo /* 10221670a1c2SRui Paulo * Now remove this module from its hash chain. We expect to always 10231670a1c2SRui Paulo * find the module on its hash chain, so in this loop we assert that 10241670a1c2SRui Paulo * we don't run off the end of the list. 10251670a1c2SRui Paulo */ 10261670a1c2SRui Paulo while (*dmpp != dmp) { 10271670a1c2SRui Paulo dmpp = &((*dmpp)->dm_next); 10281670a1c2SRui Paulo assert(*dmpp != NULL); 10291670a1c2SRui Paulo } 10301670a1c2SRui Paulo 10311670a1c2SRui Paulo *dmpp = dmp->dm_next; 10321670a1c2SRui Paulo 10336ff6d951SJohn Birrell dt_module_unload(dtp, dmp); 10346ff6d951SJohn Birrell free(dmp); 10356ff6d951SJohn Birrell } 10366ff6d951SJohn Birrell 10376ff6d951SJohn Birrell /* 10386ff6d951SJohn Birrell * Insert a new external symbol reference into the specified module. The new 10396ff6d951SJohn Birrell * symbol will be marked as undefined and is assigned a symbol index beyond 10406ff6d951SJohn Birrell * any existing cached symbols from this module. We use the ident's di_data 10416ff6d951SJohn Birrell * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol. 10426ff6d951SJohn Birrell */ 10436ff6d951SJohn Birrell dt_ident_t * 10446ff6d951SJohn Birrell dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp, 10456ff6d951SJohn Birrell const char *name, const dtrace_typeinfo_t *tip) 10466ff6d951SJohn Birrell { 10476ff6d951SJohn Birrell dtrace_syminfo_t *sip; 10486ff6d951SJohn Birrell dt_ident_t *idp; 10496ff6d951SJohn Birrell uint_t id; 10506ff6d951SJohn Birrell 10516ff6d951SJohn Birrell if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create( 10526ff6d951SJohn Birrell "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) { 10536ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM); 10546ff6d951SJohn Birrell return (NULL); 10556ff6d951SJohn Birrell } 10566ff6d951SJohn Birrell 10576ff6d951SJohn Birrell if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) { 10586ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_SYMOFLOW); 10596ff6d951SJohn Birrell return (NULL); 10606ff6d951SJohn Birrell } 10616ff6d951SJohn Birrell 10626ff6d951SJohn Birrell if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) { 10636ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM); 10646ff6d951SJohn Birrell return (NULL); 10656ff6d951SJohn Birrell } 10666ff6d951SJohn Birrell 10676ff6d951SJohn Birrell idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id, 10686ff6d951SJohn Birrell _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); 10696ff6d951SJohn Birrell 10706ff6d951SJohn Birrell if (idp == NULL) { 10716ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM); 10726ff6d951SJohn Birrell free(sip); 10736ff6d951SJohn Birrell return (NULL); 10746ff6d951SJohn Birrell } 10756ff6d951SJohn Birrell 10766ff6d951SJohn Birrell sip->dts_object = dmp->dm_name; 10776ff6d951SJohn Birrell sip->dts_name = idp->di_name; 10786ff6d951SJohn Birrell sip->dts_id = idp->di_id; 10796ff6d951SJohn Birrell 10806ff6d951SJohn Birrell idp->di_data = sip; 10816ff6d951SJohn Birrell idp->di_ctfp = tip->dtt_ctfp; 10826ff6d951SJohn Birrell idp->di_type = tip->dtt_type; 10836ff6d951SJohn Birrell 10846ff6d951SJohn Birrell return (idp); 10856ff6d951SJohn Birrell } 10866ff6d951SJohn Birrell 10876ff6d951SJohn Birrell const char * 10886ff6d951SJohn Birrell dt_module_modelname(dt_module_t *dmp) 10896ff6d951SJohn Birrell { 10906ff6d951SJohn Birrell if (dmp->dm_ops == &dt_modops_64) 10916ff6d951SJohn Birrell return ("64-bit"); 10926ff6d951SJohn Birrell else 10936ff6d951SJohn Birrell return ("32-bit"); 10946ff6d951SJohn Birrell } 10956ff6d951SJohn Birrell 10968e648814SRui Paulo /* ARGSUSED */ 10978e648814SRui Paulo int 10988e648814SRui Paulo dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp) 10998e648814SRui Paulo { 11008e648814SRui Paulo int i; 11018e648814SRui Paulo 11028e648814SRui Paulo for (i = 0; i < dmp->dm_nctflibs; i++) { 11038e648814SRui Paulo if (dmp->dm_libctfp[i] == fp) 11048e648814SRui Paulo return (i); 11058e648814SRui Paulo } 11068e648814SRui Paulo 11078e648814SRui Paulo return (-1); 11088e648814SRui Paulo } 11098e648814SRui Paulo 11108e648814SRui Paulo /* ARGSUSED */ 11118e648814SRui Paulo ctf_file_t * 11128e648814SRui Paulo dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name) 11138e648814SRui Paulo { 11148e648814SRui Paulo int i; 11158e648814SRui Paulo 11168e648814SRui Paulo for (i = 0; i < dmp->dm_nctflibs; i++) { 11178e648814SRui Paulo if (strcmp(dmp->dm_libctfn[i], name) == 0) 11188e648814SRui Paulo return (dmp->dm_libctfp[i]); 11198e648814SRui Paulo } 11208e648814SRui Paulo 11218e648814SRui Paulo return (NULL); 11228e648814SRui Paulo } 11238e648814SRui Paulo 11246ff6d951SJohn Birrell /* 11256ff6d951SJohn Birrell * Update our module cache by adding an entry for the specified module 'name'. 11266ff6d951SJohn Birrell * We create the dt_module_t and populate it using /system/object/<name>/. 1127f1e56186SJohn Birrell * 1128f1e56186SJohn Birrell * On FreeBSD, the module name is passed as the full module file name, 1129f1e56186SJohn Birrell * including the path. 11306ff6d951SJohn Birrell */ 11316ff6d951SJohn Birrell static void 1132f1e56186SJohn Birrell dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat) 11336ff6d951SJohn Birrell { 11346ff6d951SJohn Birrell char fname[MAXPATHLEN]; 11356ff6d951SJohn Birrell struct stat64 st; 11366ff6d951SJohn Birrell int fd, err, bits; 11378436cb81SMark Johnston struct module_stat ms; 11388436cb81SMark Johnston dt_kmodule_t *dkmp; 11398436cb81SMark Johnston uint_t h; 11408436cb81SMark Johnston int modid; 11416ff6d951SJohn Birrell dt_module_t *dmp; 11426ff6d951SJohn Birrell const char *s; 11436ff6d951SJohn Birrell size_t shstrs; 11446ff6d951SJohn Birrell GElf_Shdr sh; 11456ff6d951SJohn Birrell Elf_Data *dp; 11466ff6d951SJohn Birrell Elf_Scn *sp; 1147556cb98dSAndriy Gapon GElf_Ehdr ehdr; 1148f1e56186SJohn Birrell GElf_Phdr ph; 1149f1e56186SJohn Birrell char name[MAXPATHLEN]; 1150556cb98dSAndriy Gapon uintptr_t mapbase, alignmask; 1151f1e56186SJohn Birrell int i = 0; 1152556cb98dSAndriy Gapon int is_elf_obj; 1153f1e56186SJohn Birrell 1154f1e56186SJohn Birrell (void) strlcpy(name, k_stat->name, sizeof(name)); 1155f1e56186SJohn Birrell (void) strlcpy(fname, k_stat->pathname, sizeof(fname)); 11566ff6d951SJohn Birrell 11576ff6d951SJohn Birrell if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 || 11586ff6d951SJohn Birrell (dmp = dt_module_create(dtp, name)) == NULL) { 11596ff6d951SJohn Birrell dt_dprintf("failed to open %s: %s\n", fname, strerror(errno)); 11606ff6d951SJohn Birrell (void) close(fd); 11616ff6d951SJohn Birrell return; 11626ff6d951SJohn Birrell } 11636ff6d951SJohn Birrell 11646265da14SChristos Margiolis (void) strlcpy(dmp->dm_file, fname, sizeof(dmp->dm_file)); 11656265da14SChristos Margiolis dmp->dm_modid = k_stat->id; 11666265da14SChristos Margiolis 11676ff6d951SJohn Birrell /* 11686ff6d951SJohn Birrell * Since the module can unload out from under us (and /system/object 11696ff6d951SJohn Birrell * will return ENOENT), tell libelf to cook the entire file now and 11706ff6d951SJohn Birrell * then close the underlying file descriptor immediately. If this 11716ff6d951SJohn Birrell * succeeds, we know that we can continue safely using dmp->dm_elf. 11726ff6d951SJohn Birrell */ 11736ff6d951SJohn Birrell dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL); 11746ff6d951SJohn Birrell err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD); 11756ff6d951SJohn Birrell (void) close(fd); 11766ff6d951SJohn Birrell 11776ff6d951SJohn Birrell if (dmp->dm_elf == NULL || err == -1 || 11781670a1c2SRui Paulo elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) { 11796ff6d951SJohn Birrell dt_dprintf("failed to load %s: %s\n", 11806ff6d951SJohn Birrell fname, elf_errmsg(elf_errno())); 11816ff6d951SJohn Birrell dt_module_destroy(dtp, dmp); 11826ff6d951SJohn Birrell return; 11836ff6d951SJohn Birrell } 11846ff6d951SJohn Birrell 11856ff6d951SJohn Birrell switch (gelf_getclass(dmp->dm_elf)) { 11866ff6d951SJohn Birrell case ELFCLASS32: 11876ff6d951SJohn Birrell dmp->dm_ops = &dt_modops_32; 11886ff6d951SJohn Birrell bits = 32; 11896ff6d951SJohn Birrell break; 11906ff6d951SJohn Birrell case ELFCLASS64: 11916ff6d951SJohn Birrell dmp->dm_ops = &dt_modops_64; 11926ff6d951SJohn Birrell bits = 64; 11936ff6d951SJohn Birrell break; 11946ff6d951SJohn Birrell default: 11956ff6d951SJohn Birrell dt_dprintf("failed to load %s: unknown ELF class\n", fname); 11966ff6d951SJohn Birrell dt_module_destroy(dtp, dmp); 11976ff6d951SJohn Birrell return; 11986ff6d951SJohn Birrell } 1199556cb98dSAndriy Gapon mapbase = (uintptr_t)k_stat->address; 1200556cb98dSAndriy Gapon gelf_getehdr(dmp->dm_elf, &ehdr); 1201556cb98dSAndriy Gapon is_elf_obj = (ehdr.e_type == ET_REL); 1202556cb98dSAndriy Gapon if (is_elf_obj) { 1203556cb98dSAndriy Gapon dmp->dm_sec_offsets = 1204556cb98dSAndriy Gapon malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets)); 1205556cb98dSAndriy Gapon if (dmp->dm_sec_offsets == NULL) { 1206556cb98dSAndriy Gapon dt_dprintf("failed to allocate memory\n"); 1207556cb98dSAndriy Gapon dt_module_destroy(dtp, dmp); 1208556cb98dSAndriy Gapon return; 1209556cb98dSAndriy Gapon } 1210556cb98dSAndriy Gapon } 12116ff6d951SJohn Birrell /* 12126ff6d951SJohn Birrell * Iterate over the section headers locating various sections of 12136ff6d951SJohn Birrell * interest and use their attributes to flesh out the dt_module_t. 12146ff6d951SJohn Birrell */ 12156ff6d951SJohn Birrell for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { 12166ff6d951SJohn Birrell if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || 12176ff6d951SJohn Birrell (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) 12186ff6d951SJohn Birrell continue; /* skip any malformed sections */ 1219556cb98dSAndriy Gapon if (sh.sh_size == 0) 1220556cb98dSAndriy Gapon continue; 1221db4ce668SMark Johnston if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) { 1222556cb98dSAndriy Gapon alignmask = sh.sh_addralign - 1; 1223556cb98dSAndriy Gapon mapbase += alignmask; 1224556cb98dSAndriy Gapon mapbase &= ~alignmask; 1225556cb98dSAndriy Gapon sh.sh_addr = mapbase; 1226db4ce668SMark Johnston if (is_elf_obj) 1227556cb98dSAndriy Gapon dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr; 1228556cb98dSAndriy Gapon mapbase += sh.sh_size; 1229556cb98dSAndriy Gapon } 12306ff6d951SJohn Birrell if (strcmp(s, ".text") == 0) { 12316ff6d951SJohn Birrell dmp->dm_text_size = sh.sh_size; 12326ff6d951SJohn Birrell dmp->dm_text_va = sh.sh_addr; 12336ff6d951SJohn Birrell } else if (strcmp(s, ".data") == 0) { 12346ff6d951SJohn Birrell dmp->dm_data_size = sh.sh_size; 12356ff6d951SJohn Birrell dmp->dm_data_va = sh.sh_addr; 12366ff6d951SJohn Birrell } else if (strcmp(s, ".bss") == 0) { 12376ff6d951SJohn Birrell dmp->dm_bss_size = sh.sh_size; 12386ff6d951SJohn Birrell dmp->dm_bss_va = sh.sh_addr; 12396ff6d951SJohn Birrell } else if (strcmp(s, ".info") == 0 && 12406ff6d951SJohn Birrell (dp = elf_getdata(sp, NULL)) != NULL) { 12416ff6d951SJohn Birrell bcopy(dp->d_buf, &dmp->dm_info, 12426ff6d951SJohn Birrell MIN(sh.sh_size, sizeof (dmp->dm_info))); 12436ff6d951SJohn Birrell } 12446ff6d951SJohn Birrell } 12456ff6d951SJohn Birrell 12466ff6d951SJohn Birrell dmp->dm_flags |= DT_DM_KERNEL; 1247556cb98dSAndriy Gapon /* 1248556cb98dSAndriy Gapon * Include .rodata and special sections into .text. 1249556cb98dSAndriy Gapon * This depends on default section layout produced by GNU ld 1250556cb98dSAndriy Gapon * for ELF objects and libraries: 1251556cb98dSAndriy Gapon * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable] 1252556cb98dSAndriy Gapon */ 1253556cb98dSAndriy Gapon dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va; 1254*7bbcbd43SMark Johnston 1255*7bbcbd43SMark Johnston if (!is_elf_obj) { 1256f1e56186SJohn Birrell /* 1257f1e56186SJohn Birrell * Find the first load section and figure out the relocation 1258f1e56186SJohn Birrell * offset for the symbols. The kernel module will not need 1259f1e56186SJohn Birrell * relocation, but the kernel linker modules will. 1260f1e56186SJohn Birrell */ 1261f1e56186SJohn Birrell for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) { 1262f1e56186SJohn Birrell if (ph.p_type == PT_LOAD) { 1263*7bbcbd43SMark Johnston dmp->dm_reloc_offset = 1264*7bbcbd43SMark Johnston k_stat->address - ph.p_vaddr; 1265f1e56186SJohn Birrell break; 1266f1e56186SJohn Birrell } 1267f1e56186SJohn Birrell } 1268*7bbcbd43SMark Johnston } 12696ff6d951SJohn Birrell 12706ff6d951SJohn Birrell if (dmp->dm_info.objfs_info_primary) 12716ff6d951SJohn Birrell dmp->dm_flags |= DT_DM_PRIMARY; 12726ff6d951SJohn Birrell 12738436cb81SMark Johnston ms.version = sizeof(ms); 12748436cb81SMark Johnston for (modid = kldfirstmod(k_stat->id); modid > 0; 12758436cb81SMark Johnston modid = modnext(modid)) { 12768436cb81SMark Johnston if (modstat(modid, &ms) != 0) { 12778436cb81SMark Johnston dt_dprintf("modstat failed for id %d in %s: %s\n", 12788436cb81SMark Johnston modid, k_stat->name, strerror(errno)); 12798436cb81SMark Johnston continue; 12808436cb81SMark Johnston } 12818436cb81SMark Johnston if (dt_kmodule_lookup(dtp, ms.name) != NULL) 12828436cb81SMark Johnston continue; 12838436cb81SMark Johnston 12848436cb81SMark Johnston dkmp = malloc(sizeof (*dkmp)); 12858436cb81SMark Johnston if (dkmp == NULL) { 12868436cb81SMark Johnston dt_dprintf("failed to allocate memory\n"); 12878436cb81SMark Johnston dt_module_destroy(dtp, dmp); 12888436cb81SMark Johnston return; 12898436cb81SMark Johnston } 12908436cb81SMark Johnston 12918436cb81SMark Johnston h = dt_strtab_hash(ms.name, NULL) % dtp->dt_modbuckets; 12928436cb81SMark Johnston dkmp->dkm_next = dtp->dt_kmods[h]; 12938436cb81SMark Johnston dkmp->dkm_name = strdup(ms.name); 12948436cb81SMark Johnston dkmp->dkm_module = dmp; 12958436cb81SMark Johnston dtp->dt_kmods[h] = dkmp; 12968436cb81SMark Johnston } 12978436cb81SMark Johnston 12986ff6d951SJohn Birrell dt_dprintf("opened %d-bit module %s (%s) [%d]\n", 12996ff6d951SJohn Birrell bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid); 13006ff6d951SJohn Birrell } 13016ff6d951SJohn Birrell 13026ff6d951SJohn Birrell /* 13036ff6d951SJohn Birrell * Unload all the loaded modules and then refresh the module cache with the 13046ff6d951SJohn Birrell * latest list of loaded modules and their address ranges. 13056ff6d951SJohn Birrell */ 13066ff6d951SJohn Birrell void 13076ff6d951SJohn Birrell dtrace_update(dtrace_hdl_t *dtp) 13086ff6d951SJohn Birrell { 13096ff6d951SJohn Birrell dt_module_t *dmp; 13106ff6d951SJohn Birrell DIR *dirp; 1311f1e56186SJohn Birrell #if defined(__FreeBSD__) 1312f1e56186SJohn Birrell int fileid; 1313f1e56186SJohn Birrell #endif 13146ff6d951SJohn Birrell 13156ff6d951SJohn Birrell for (dmp = dt_list_next(&dtp->dt_modlist); 13166ff6d951SJohn Birrell dmp != NULL; dmp = dt_list_next(dmp)) 13176ff6d951SJohn Birrell dt_module_unload(dtp, dmp); 13186ff6d951SJohn Birrell 1319bc96366cSSteven Hartland #ifdef illumos 13206ff6d951SJohn Birrell /* 13216ff6d951SJohn Birrell * Open /system/object and attempt to create a libdtrace module for 13226ff6d951SJohn Birrell * each kernel module that is loaded on the current system. 13236ff6d951SJohn Birrell */ 13246ff6d951SJohn Birrell if (!(dtp->dt_oflags & DTRACE_O_NOSYS) && 13256ff6d951SJohn Birrell (dirp = opendir(OBJFS_ROOT)) != NULL) { 13266ff6d951SJohn Birrell struct dirent *dp; 13276ff6d951SJohn Birrell 13286ff6d951SJohn Birrell while ((dp = readdir(dirp)) != NULL) { 13296ff6d951SJohn Birrell if (dp->d_name[0] != '.') 13306ff6d951SJohn Birrell dt_module_update(dtp, dp->d_name); 13316ff6d951SJohn Birrell } 13326ff6d951SJohn Birrell 13336ff6d951SJohn Birrell (void) closedir(dirp); 13346ff6d951SJohn Birrell } 1335f1e56186SJohn Birrell #elif defined(__FreeBSD__) 1336f1e56186SJohn Birrell /* 1337f1e56186SJohn Birrell * Use FreeBSD's kernel loader interface to discover what kernel 1338f1e56186SJohn Birrell * modules are loaded and create a libdtrace module for each one. 1339f1e56186SJohn Birrell */ 1340f1e56186SJohn Birrell for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 1341f1e56186SJohn Birrell struct kld_file_stat k_stat; 1342f1e56186SJohn Birrell k_stat.version = sizeof(k_stat); 1343f1e56186SJohn Birrell if (kldstat(fileid, &k_stat) == 0) 1344f1e56186SJohn Birrell dt_module_update(dtp, &k_stat); 1345f1e56186SJohn Birrell } 1346f1e56186SJohn Birrell #endif 13476ff6d951SJohn Birrell 13486ff6d951SJohn Birrell /* 13496ff6d951SJohn Birrell * Look up all the macro identifiers and set di_id to the latest value. 13506ff6d951SJohn Birrell * This code collaborates with dt_lex.l on the use of di_id. We will 13516ff6d951SJohn Birrell * need to implement something fancier if we need to support non-ints. 13526ff6d951SJohn Birrell */ 13536ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid(); 13546ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid(); 13556ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid(); 13566ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid(); 13576ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0); 13586ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid(); 1359bc96366cSSteven Hartland #ifdef illumos 13606ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid(); 1361f1e56186SJohn Birrell #endif 13626ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0); 1363bc96366cSSteven Hartland #ifdef illumos 13646ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid(); 1365f1e56186SJohn Birrell #endif 13666ff6d951SJohn Birrell dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid(); 13676ff6d951SJohn Birrell 13686ff6d951SJohn Birrell /* 13696ff6d951SJohn Birrell * Cache the pointers to the modules representing the base executable 13706ff6d951SJohn Birrell * and the run-time linker in the dtrace client handle. Note that on 13716ff6d951SJohn Birrell * x86 krtld is folded into unix, so if we don't find it, use unix 13726ff6d951SJohn Birrell * instead. 13736ff6d951SJohn Birrell */ 13746ff6d951SJohn Birrell dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix"); 13756ff6d951SJohn Birrell dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld"); 13766ff6d951SJohn Birrell if (dtp->dt_rtld == NULL) 13776ff6d951SJohn Birrell dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix"); 13786ff6d951SJohn Birrell 13796ff6d951SJohn Birrell /* 13806ff6d951SJohn Birrell * If this is the first time we are initializing the module list, 13816ff6d951SJohn Birrell * remove the module for genunix from the module list and then move it 13826ff6d951SJohn Birrell * to the front of the module list. We do this so that type and symbol 13836ff6d951SJohn Birrell * queries encounter genunix and thereby optimize for the common case 13846ff6d951SJohn Birrell * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below. 13856ff6d951SJohn Birrell */ 13866ff6d951SJohn Birrell if (dtp->dt_exec != NULL && 13876ff6d951SJohn Birrell dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) { 13886ff6d951SJohn Birrell dt_list_delete(&dtp->dt_modlist, dtp->dt_exec); 13896ff6d951SJohn Birrell dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec); 13906ff6d951SJohn Birrell } 13916ff6d951SJohn Birrell } 13926ff6d951SJohn Birrell 13936ff6d951SJohn Birrell static dt_module_t * 13946ff6d951SJohn Birrell dt_module_from_object(dtrace_hdl_t *dtp, const char *object) 13956ff6d951SJohn Birrell { 13966ff6d951SJohn Birrell int err = EDT_NOMOD; 13976ff6d951SJohn Birrell dt_module_t *dmp; 13986ff6d951SJohn Birrell 13996ff6d951SJohn Birrell switch ((uintptr_t)object) { 14006ff6d951SJohn Birrell case (uintptr_t)DTRACE_OBJ_EXEC: 14016ff6d951SJohn Birrell dmp = dtp->dt_exec; 14026ff6d951SJohn Birrell break; 14036ff6d951SJohn Birrell case (uintptr_t)DTRACE_OBJ_RTLD: 14046ff6d951SJohn Birrell dmp = dtp->dt_rtld; 14056ff6d951SJohn Birrell break; 14066ff6d951SJohn Birrell case (uintptr_t)DTRACE_OBJ_CDEFS: 14076ff6d951SJohn Birrell dmp = dtp->dt_cdefs; 14086ff6d951SJohn Birrell break; 14096ff6d951SJohn Birrell case (uintptr_t)DTRACE_OBJ_DDEFS: 14106ff6d951SJohn Birrell dmp = dtp->dt_ddefs; 14116ff6d951SJohn Birrell break; 14126ff6d951SJohn Birrell default: 14136ff6d951SJohn Birrell dmp = dt_module_create(dtp, object); 14146ff6d951SJohn Birrell err = EDT_NOMEM; 14156ff6d951SJohn Birrell } 14166ff6d951SJohn Birrell 14176ff6d951SJohn Birrell if (dmp == NULL) 14186ff6d951SJohn Birrell (void) dt_set_errno(dtp, err); 14196ff6d951SJohn Birrell 14206ff6d951SJohn Birrell return (dmp); 14216ff6d951SJohn Birrell } 14226ff6d951SJohn Birrell 14236ff6d951SJohn Birrell /* 14246ff6d951SJohn Birrell * Exported interface to look up a symbol by name. We return the GElf_Sym and 14256ff6d951SJohn Birrell * complete symbol information for the matching symbol. 14266ff6d951SJohn Birrell */ 14276ff6d951SJohn Birrell int 14286ff6d951SJohn Birrell dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name, 14296ff6d951SJohn Birrell GElf_Sym *symp, dtrace_syminfo_t *sip) 14306ff6d951SJohn Birrell { 14316ff6d951SJohn Birrell dt_module_t *dmp; 14326ff6d951SJohn Birrell dt_ident_t *idp; 14336ff6d951SJohn Birrell uint_t n, id; 14346ff6d951SJohn Birrell GElf_Sym sym; 14356ff6d951SJohn Birrell 14366ff6d951SJohn Birrell uint_t mask = 0; /* mask of dt_module flags to match */ 14376ff6d951SJohn Birrell uint_t bits = 0; /* flag bits that must be present */ 14386ff6d951SJohn Birrell 14396ff6d951SJohn Birrell if (object != DTRACE_OBJ_EVERY && 14406ff6d951SJohn Birrell object != DTRACE_OBJ_KMODS && 14416ff6d951SJohn Birrell object != DTRACE_OBJ_UMODS) { 14426ff6d951SJohn Birrell if ((dmp = dt_module_from_object(dtp, object)) == NULL) 14436ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 14446ff6d951SJohn Birrell 14456ff6d951SJohn Birrell if (dt_module_load(dtp, dmp) == -1) 14466ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 14476ff6d951SJohn Birrell n = 1; 14486ff6d951SJohn Birrell 14496ff6d951SJohn Birrell } else { 14506ff6d951SJohn Birrell if (object == DTRACE_OBJ_KMODS) 14516ff6d951SJohn Birrell mask = bits = DT_DM_KERNEL; 14526ff6d951SJohn Birrell else if (object == DTRACE_OBJ_UMODS) 14536ff6d951SJohn Birrell mask = DT_DM_KERNEL; 14546ff6d951SJohn Birrell 14556ff6d951SJohn Birrell dmp = dt_list_next(&dtp->dt_modlist); 14566ff6d951SJohn Birrell n = dtp->dt_nmods; 14576ff6d951SJohn Birrell } 14586ff6d951SJohn Birrell 14596ff6d951SJohn Birrell if (symp == NULL) 14606ff6d951SJohn Birrell symp = &sym; 14616ff6d951SJohn Birrell 14626ff6d951SJohn Birrell for (; n > 0; n--, dmp = dt_list_next(dmp)) { 14636ff6d951SJohn Birrell if ((dmp->dm_flags & mask) != bits) 14646ff6d951SJohn Birrell continue; /* failed to match required attributes */ 14656ff6d951SJohn Birrell 14666ff6d951SJohn Birrell if (dt_module_load(dtp, dmp) == -1) 14676ff6d951SJohn Birrell continue; /* failed to load symbol table */ 14686ff6d951SJohn Birrell 14696ff6d951SJohn Birrell if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) { 14706ff6d951SJohn Birrell if (sip != NULL) { 14716ff6d951SJohn Birrell sip->dts_object = dmp->dm_name; 14726ff6d951SJohn Birrell sip->dts_name = (const char *) 14736ff6d951SJohn Birrell dmp->dm_strtab.cts_data + symp->st_name; 14746ff6d951SJohn Birrell sip->dts_id = id; 14756ff6d951SJohn Birrell } 14766ff6d951SJohn Birrell return (0); 14776ff6d951SJohn Birrell } 14786ff6d951SJohn Birrell 14796ff6d951SJohn Birrell if (dmp->dm_extern != NULL && 14806ff6d951SJohn Birrell (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) { 14816ff6d951SJohn Birrell if (symp != &sym) { 14826ff6d951SJohn Birrell symp->st_name = (uintptr_t)idp->di_name; 14836ff6d951SJohn Birrell symp->st_info = 14846ff6d951SJohn Birrell GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); 14856ff6d951SJohn Birrell symp->st_other = 0; 14866ff6d951SJohn Birrell symp->st_shndx = SHN_UNDEF; 14876ff6d951SJohn Birrell symp->st_value = 0; 14886ff6d951SJohn Birrell symp->st_size = 14896ff6d951SJohn Birrell ctf_type_size(idp->di_ctfp, idp->di_type); 14906ff6d951SJohn Birrell } 14916ff6d951SJohn Birrell 14926ff6d951SJohn Birrell if (sip != NULL) { 14936ff6d951SJohn Birrell sip->dts_object = dmp->dm_name; 14946ff6d951SJohn Birrell sip->dts_name = idp->di_name; 14956ff6d951SJohn Birrell sip->dts_id = idp->di_id; 14966ff6d951SJohn Birrell } 14976ff6d951SJohn Birrell 14986ff6d951SJohn Birrell return (0); 14996ff6d951SJohn Birrell } 15006ff6d951SJohn Birrell } 15016ff6d951SJohn Birrell 15026ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOSYM)); 15036ff6d951SJohn Birrell } 15046ff6d951SJohn Birrell 15056ff6d951SJohn Birrell /* 15066ff6d951SJohn Birrell * Exported interface to look up a symbol by address. We return the GElf_Sym 15076ff6d951SJohn Birrell * and complete symbol information for the matching symbol. 15086ff6d951SJohn Birrell */ 15096ff6d951SJohn Birrell int 15106ff6d951SJohn Birrell dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr, 15116ff6d951SJohn Birrell GElf_Sym *symp, dtrace_syminfo_t *sip) 15126ff6d951SJohn Birrell { 15136ff6d951SJohn Birrell dt_module_t *dmp; 15146ff6d951SJohn Birrell uint_t id; 15156ff6d951SJohn Birrell const dtrace_vector_t *v = dtp->dt_vector; 15166ff6d951SJohn Birrell 15176ff6d951SJohn Birrell if (v != NULL) 15186ff6d951SJohn Birrell return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip)); 15196ff6d951SJohn Birrell 15206ff6d951SJohn Birrell for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; 15216ff6d951SJohn Birrell dmp = dt_list_next(dmp)) { 15226ff6d951SJohn Birrell if (addr - dmp->dm_text_va < dmp->dm_text_size || 15236ff6d951SJohn Birrell addr - dmp->dm_data_va < dmp->dm_data_size || 15246ff6d951SJohn Birrell addr - dmp->dm_bss_va < dmp->dm_bss_size) 15256ff6d951SJohn Birrell break; 15266ff6d951SJohn Birrell } 15276ff6d951SJohn Birrell 15286ff6d951SJohn Birrell if (dmp == NULL) 15296ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOSYMADDR)); 15306ff6d951SJohn Birrell 15316ff6d951SJohn Birrell if (dt_module_load(dtp, dmp) == -1) 15326ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 15336ff6d951SJohn Birrell 15346ff6d951SJohn Birrell if (symp != NULL) { 15356ff6d951SJohn Birrell if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL) 15366ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOSYMADDR)); 15376ff6d951SJohn Birrell } 15386ff6d951SJohn Birrell 15396ff6d951SJohn Birrell if (sip != NULL) { 15406ff6d951SJohn Birrell sip->dts_object = dmp->dm_name; 15416ff6d951SJohn Birrell 15426ff6d951SJohn Birrell if (symp != NULL) { 15436ff6d951SJohn Birrell sip->dts_name = (const char *) 15446ff6d951SJohn Birrell dmp->dm_strtab.cts_data + symp->st_name; 15456ff6d951SJohn Birrell sip->dts_id = id; 15466ff6d951SJohn Birrell } else { 15476ff6d951SJohn Birrell sip->dts_name = NULL; 15486ff6d951SJohn Birrell sip->dts_id = 0; 15496ff6d951SJohn Birrell } 15506ff6d951SJohn Birrell } 15516ff6d951SJohn Birrell 15526ff6d951SJohn Birrell return (0); 15536ff6d951SJohn Birrell } 15546ff6d951SJohn Birrell 15556ff6d951SJohn Birrell int 15566ff6d951SJohn Birrell dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, 15576ff6d951SJohn Birrell dtrace_typeinfo_t *tip) 15586ff6d951SJohn Birrell { 15596ff6d951SJohn Birrell dtrace_typeinfo_t ti; 15606ff6d951SJohn Birrell dt_module_t *dmp; 15616ff6d951SJohn Birrell int found = 0; 15626ff6d951SJohn Birrell ctf_id_t id; 15638e648814SRui Paulo uint_t n, i; 15646ff6d951SJohn Birrell int justone; 15658e648814SRui Paulo ctf_file_t *fp; 15668e648814SRui Paulo char *buf, *p, *q; 15676ff6d951SJohn Birrell 15686ff6d951SJohn Birrell uint_t mask = 0; /* mask of dt_module flags to match */ 15696ff6d951SJohn Birrell uint_t bits = 0; /* flag bits that must be present */ 15706ff6d951SJohn Birrell 15716ff6d951SJohn Birrell if (object != DTRACE_OBJ_EVERY && 15726ff6d951SJohn Birrell object != DTRACE_OBJ_KMODS && 15736ff6d951SJohn Birrell object != DTRACE_OBJ_UMODS) { 15746ff6d951SJohn Birrell if ((dmp = dt_module_from_object(dtp, object)) == NULL) 15756ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 15766ff6d951SJohn Birrell 15776ff6d951SJohn Birrell if (dt_module_load(dtp, dmp) == -1) 15786ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 15796ff6d951SJohn Birrell n = 1; 15806ff6d951SJohn Birrell justone = 1; 15816ff6d951SJohn Birrell } else { 15826ff6d951SJohn Birrell if (object == DTRACE_OBJ_KMODS) 15836ff6d951SJohn Birrell mask = bits = DT_DM_KERNEL; 15846ff6d951SJohn Birrell else if (object == DTRACE_OBJ_UMODS) 15856ff6d951SJohn Birrell mask = DT_DM_KERNEL; 15866ff6d951SJohn Birrell 15876ff6d951SJohn Birrell dmp = dt_list_next(&dtp->dt_modlist); 15886ff6d951SJohn Birrell n = dtp->dt_nmods; 15896ff6d951SJohn Birrell justone = 0; 15906ff6d951SJohn Birrell } 15916ff6d951SJohn Birrell 15926ff6d951SJohn Birrell if (tip == NULL) 15936ff6d951SJohn Birrell tip = &ti; 15946ff6d951SJohn Birrell 15956ff6d951SJohn Birrell for (; n > 0; n--, dmp = dt_list_next(dmp)) { 15966ff6d951SJohn Birrell if ((dmp->dm_flags & mask) != bits) 15976ff6d951SJohn Birrell continue; /* failed to match required attributes */ 15986ff6d951SJohn Birrell 15996ff6d951SJohn Birrell /* 16006ff6d951SJohn Birrell * If we can't load the CTF container, continue on to the next 16016ff6d951SJohn Birrell * module. If our search was scoped to only one module then 16026ff6d951SJohn Birrell * return immediately leaving dt_errno unmodified. 16036ff6d951SJohn Birrell */ 16048e648814SRui Paulo if (dt_module_hasctf(dtp, dmp) == 0) { 16056ff6d951SJohn Birrell if (justone) 16066ff6d951SJohn Birrell return (-1); 16076ff6d951SJohn Birrell continue; 16086ff6d951SJohn Birrell } 16096ff6d951SJohn Birrell 16106ff6d951SJohn Birrell /* 16116ff6d951SJohn Birrell * Look up the type in the module's CTF container. If our 16126ff6d951SJohn Birrell * match is a forward declaration tag, save this choice in 16136ff6d951SJohn Birrell * 'tip' and keep going in the hope that we will locate the 16146ff6d951SJohn Birrell * underlying structure definition. Otherwise just return. 16156ff6d951SJohn Birrell */ 16168e648814SRui Paulo if (dmp->dm_pid == 0) { 16178e648814SRui Paulo id = ctf_lookup_by_name(dmp->dm_ctfp, name); 16188e648814SRui Paulo fp = dmp->dm_ctfp; 16198e648814SRui Paulo } else { 16208e648814SRui Paulo if ((p = strchr(name, '`')) != NULL) { 16218e648814SRui Paulo buf = strdup(name); 16228e648814SRui Paulo if (buf == NULL) 16238e648814SRui Paulo return (dt_set_errno(dtp, EDT_NOMEM)); 16248e648814SRui Paulo p = strchr(buf, '`'); 16258e648814SRui Paulo if ((q = strchr(p + 1, '`')) != NULL) 16268e648814SRui Paulo p = q; 16278e648814SRui Paulo *p = '\0'; 16288e648814SRui Paulo fp = dt_module_getctflib(dtp, dmp, buf); 16298e648814SRui Paulo if (fp == NULL || (id = ctf_lookup_by_name(fp, 16308e648814SRui Paulo p + 1)) == CTF_ERR) 16318e648814SRui Paulo id = CTF_ERR; 16328e648814SRui Paulo free(buf); 16338e648814SRui Paulo } else { 16348e648814SRui Paulo for (i = 0; i < dmp->dm_nctflibs; i++) { 16358e648814SRui Paulo fp = dmp->dm_libctfp[i]; 16368e648814SRui Paulo id = ctf_lookup_by_name(fp, name); 16378e648814SRui Paulo if (id != CTF_ERR) 16388e648814SRui Paulo break; 16398e648814SRui Paulo } 16408e648814SRui Paulo } 16418e648814SRui Paulo } 16428e648814SRui Paulo if (id != CTF_ERR) { 16436ff6d951SJohn Birrell tip->dtt_object = dmp->dm_name; 16448e648814SRui Paulo tip->dtt_ctfp = fp; 16456ff6d951SJohn Birrell tip->dtt_type = id; 16468e648814SRui Paulo if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) != 16478e648814SRui Paulo CTF_K_FORWARD) 16486ff6d951SJohn Birrell return (0); 16496ff6d951SJohn Birrell 16506ff6d951SJohn Birrell found++; 16516ff6d951SJohn Birrell } 16526ff6d951SJohn Birrell } 16536ff6d951SJohn Birrell 16546ff6d951SJohn Birrell if (found == 0) 16556ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOTYPE)); 16566ff6d951SJohn Birrell 16576ff6d951SJohn Birrell return (0); 16586ff6d951SJohn Birrell } 16596ff6d951SJohn Birrell 16606ff6d951SJohn Birrell int 16616ff6d951SJohn Birrell dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp, 16626ff6d951SJohn Birrell const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip) 16636ff6d951SJohn Birrell { 16646ff6d951SJohn Birrell dt_module_t *dmp; 16656ff6d951SJohn Birrell 16666ff6d951SJohn Birrell tip->dtt_object = NULL; 16676ff6d951SJohn Birrell tip->dtt_ctfp = NULL; 16686ff6d951SJohn Birrell tip->dtt_type = CTF_ERR; 16698e648814SRui Paulo tip->dtt_flags = 0; 16706ff6d951SJohn Birrell 16716ff6d951SJohn Birrell if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) 16726ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMOD)); 16736ff6d951SJohn Birrell 16746ff6d951SJohn Birrell if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) { 16756ff6d951SJohn Birrell dt_ident_t *idp = 16766ff6d951SJohn Birrell dt_idhash_lookup(dmp->dm_extern, sip->dts_name); 16776ff6d951SJohn Birrell 16786ff6d951SJohn Birrell if (idp == NULL) 16796ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOSYM)); 16806ff6d951SJohn Birrell 16816ff6d951SJohn Birrell tip->dtt_ctfp = idp->di_ctfp; 16826ff6d951SJohn Birrell tip->dtt_type = idp->di_type; 16836ff6d951SJohn Birrell 16846ff6d951SJohn Birrell } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) { 16856ff6d951SJohn Birrell if (dt_module_getctf(dtp, dmp) == NULL) 16866ff6d951SJohn Birrell return (-1); /* errno is set for us */ 16876ff6d951SJohn Birrell 16886ff6d951SJohn Birrell tip->dtt_ctfp = dmp->dm_ctfp; 16896ff6d951SJohn Birrell tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id); 16906ff6d951SJohn Birrell 16916ff6d951SJohn Birrell if (tip->dtt_type == CTF_ERR) { 16926ff6d951SJohn Birrell dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp); 16936ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_CTF)); 16946ff6d951SJohn Birrell } 16956ff6d951SJohn Birrell 16966ff6d951SJohn Birrell } else { 16976ff6d951SJohn Birrell tip->dtt_ctfp = DT_FPTR_CTFP(dtp); 16986ff6d951SJohn Birrell tip->dtt_type = DT_FPTR_TYPE(dtp); 16996ff6d951SJohn Birrell } 17006ff6d951SJohn Birrell 17016ff6d951SJohn Birrell tip->dtt_object = dmp->dm_name; 17026ff6d951SJohn Birrell return (0); 17036ff6d951SJohn Birrell } 17046ff6d951SJohn Birrell 17056ff6d951SJohn Birrell static dtrace_objinfo_t * 17066ff6d951SJohn Birrell dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto) 17076ff6d951SJohn Birrell { 17086ff6d951SJohn Birrell dto->dto_name = dmp->dm_name; 17096ff6d951SJohn Birrell dto->dto_file = dmp->dm_file; 17106ff6d951SJohn Birrell dto->dto_id = dmp->dm_modid; 17116ff6d951SJohn Birrell dto->dto_flags = 0; 17126ff6d951SJohn Birrell 17136ff6d951SJohn Birrell if (dmp->dm_flags & DT_DM_KERNEL) 17146ff6d951SJohn Birrell dto->dto_flags |= DTRACE_OBJ_F_KERNEL; 17156ff6d951SJohn Birrell if (dmp->dm_flags & DT_DM_PRIMARY) 17166ff6d951SJohn Birrell dto->dto_flags |= DTRACE_OBJ_F_PRIMARY; 17176ff6d951SJohn Birrell 17186ff6d951SJohn Birrell dto->dto_text_va = dmp->dm_text_va; 17196ff6d951SJohn Birrell dto->dto_text_size = dmp->dm_text_size; 17206ff6d951SJohn Birrell dto->dto_data_va = dmp->dm_data_va; 17216ff6d951SJohn Birrell dto->dto_data_size = dmp->dm_data_size; 17226ff6d951SJohn Birrell dto->dto_bss_va = dmp->dm_bss_va; 17236ff6d951SJohn Birrell dto->dto_bss_size = dmp->dm_bss_size; 17246ff6d951SJohn Birrell 17256ff6d951SJohn Birrell return (dto); 17266ff6d951SJohn Birrell } 17276ff6d951SJohn Birrell 17286ff6d951SJohn Birrell int 17296ff6d951SJohn Birrell dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data) 17306ff6d951SJohn Birrell { 17316ff6d951SJohn Birrell const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist); 17326ff6d951SJohn Birrell dtrace_objinfo_t dto; 17336ff6d951SJohn Birrell int rv; 17346ff6d951SJohn Birrell 17356ff6d951SJohn Birrell for (; dmp != NULL; dmp = dt_list_next(dmp)) { 17366ff6d951SJohn Birrell if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0) 17376ff6d951SJohn Birrell return (rv); 17386ff6d951SJohn Birrell } 17396ff6d951SJohn Birrell 17406ff6d951SJohn Birrell return (0); 17416ff6d951SJohn Birrell } 17426ff6d951SJohn Birrell 17436ff6d951SJohn Birrell int 17446ff6d951SJohn Birrell dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto) 17456ff6d951SJohn Birrell { 17466ff6d951SJohn Birrell dt_module_t *dmp; 17476ff6d951SJohn Birrell 17486ff6d951SJohn Birrell if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS || 17496ff6d951SJohn Birrell object == DTRACE_OBJ_UMODS || dto == NULL) 17506ff6d951SJohn Birrell return (dt_set_errno(dtp, EINVAL)); 17516ff6d951SJohn Birrell 17526ff6d951SJohn Birrell if ((dmp = dt_module_from_object(dtp, object)) == NULL) 17536ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 17546ff6d951SJohn Birrell 17556ff6d951SJohn Birrell if (dt_module_load(dtp, dmp) == -1) 17566ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */ 17576ff6d951SJohn Birrell 17586ff6d951SJohn Birrell (void) dt_module_info(dmp, dto); 17596ff6d951SJohn Birrell return (0); 17606ff6d951SJohn Birrell } 1761