1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright (c) 1997-1999 by Sun Microsystems, Inc. 24 0 stevel * All rights reserved. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <stdio.h> 30 0 stevel #include <fcntl.h> 31 0 stevel #include <ctype.h> 32 0 stevel #include <string.h> 33 0 stevel #include <signal.h> 34 0 stevel #include <errno.h> 35 0 stevel #include <stdlib.h> 36 0 stevel #include <stdarg.h> 37 0 stevel #include <unistd.h> 38 0 stevel #include <limits.h> 39 0 stevel #include <sys/types.h> 40 0 stevel #include <sys/stat.h> 41 0 stevel 42 0 stevel #include <libelf.h> 43 0 stevel #include <link.h> 44 0 stevel #include <elf.h> 45 0 stevel #include <sys/machelf.h> 46 0 stevel 47 0 stevel #include <kstat.h> 48 0 stevel #include <sys/cpuvar.h> 49 0 stevel 50 0 stevel typedef struct syment { 51 0 stevel uintptr_t addr; 52 0 stevel char *name; 53 0 stevel size_t size; 54 0 stevel } syment_t; 55 0 stevel 56 0 stevel static syment_t *symbol_table; 57 0 stevel static int nsyms, maxsyms; 58 0 stevel static char maxsymname[64]; 59 0 stevel 60 0 stevel #ifdef _ELF64 61 0 stevel #define elf_getshdr elf64_getshdr 62 0 stevel #else 63 0 stevel #define elf_getshdr elf32_getshdr 64 0 stevel #endif 65 0 stevel 66 0 stevel static void 67 0 stevel add_symbol(char *name, uintptr_t addr, size_t size) 68 0 stevel { 69 0 stevel syment_t *sep; 70 0 stevel 71 0 stevel if (nsyms >= maxsyms) { 72 0 stevel maxsyms += 10000; 73 0 stevel symbol_table = realloc(symbol_table, maxsyms * sizeof (*sep)); 74 0 stevel if (symbol_table == NULL) { 75 0 stevel (void) fprintf(stderr, "can't allocate symbol table\n"); 76 0 stevel exit(3); 77 0 stevel } 78 0 stevel } 79 0 stevel sep = &symbol_table[nsyms++]; 80 0 stevel 81 0 stevel sep->name = name; 82 0 stevel sep->addr = addr; 83 0 stevel sep->size = size; 84 0 stevel } 85 0 stevel 86 0 stevel static void 87 0 stevel remove_symbol(uintptr_t addr) 88 0 stevel { 89 0 stevel int i; 90 0 stevel syment_t *sep = symbol_table; 91 0 stevel 92 0 stevel for (i = 0; i < nsyms; i++, sep++) 93 0 stevel if (sep->addr == addr) 94 0 stevel sep->addr = 0; 95 0 stevel } 96 0 stevel 97 0 stevel static void 98 0 stevel fake_up_certain_popular_kernel_symbols(void) 99 0 stevel { 100 0 stevel kstat_ctl_t *kc; 101 0 stevel kstat_t *ksp; 102 0 stevel char *name; 103 0 stevel 104 0 stevel if ((kc = kstat_open()) == NULL) 105 0 stevel return; 106 0 stevel 107 0 stevel for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 108 0 stevel if (strcmp(ksp->ks_module, "cpu_info") == 0) { 109 0 stevel if ((name = malloc(20)) == NULL) 110 0 stevel break; 111 0 stevel /* 112 0 stevel * For consistency, keep cpu[0] and toss cpu0 113 0 stevel * or any other such symbols. 114 0 stevel */ 115 0 stevel if (ksp->ks_instance == 0) 116 0 stevel remove_symbol((uintptr_t)ksp->ks_private); 117 0 stevel (void) sprintf(name, "cpu[%d]", ksp->ks_instance); 118 0 stevel add_symbol(name, (uintptr_t)ksp->ks_private, 119 0 stevel sizeof (struct cpu)); 120 0 stevel } 121 0 stevel } 122 0 stevel (void) kstat_close(kc); 123 0 stevel } 124 0 stevel 125 0 stevel static int 126 0 stevel symcmp(const void *p1, const void *p2) 127 0 stevel { 128 0 stevel uintptr_t a1 = ((syment_t *)p1)->addr; 129 0 stevel uintptr_t a2 = ((syment_t *)p2)->addr; 130 0 stevel 131 0 stevel if (a1 < a2) 132 0 stevel return (-1); 133 0 stevel if (a1 > a2) 134 0 stevel return (1); 135 0 stevel return (0); 136 0 stevel } 137 0 stevel 138 0 stevel int 139 0 stevel symtab_init(void) 140 0 stevel { 141 0 stevel Elf *elf; 142 0 stevel Elf_Scn *scn = NULL; 143 0 stevel Sym *symtab, *symp, *lastsym; 144 0 stevel char *strtab; 145 0 stevel uint_t cnt; 146 0 stevel int fd; 147 0 stevel int i; 148 0 stevel int strindex = -1; 149 0 stevel 150 0 stevel if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) 151 0 stevel return (-1); 152 0 stevel 153 0 stevel (void) elf_version(EV_CURRENT); 154 0 stevel 155 0 stevel elf = elf_begin(fd, ELF_C_READ, NULL); 156 0 stevel 157 0 stevel for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) { 158 0 stevel Shdr *shdr = elf_getshdr(scn); 159 0 stevel if (shdr->sh_type == SHT_SYMTAB) { 160 0 stevel symtab = (Sym *)elf_getdata(scn, NULL)->d_buf; 161 0 stevel nsyms = shdr->sh_size / shdr->sh_entsize; 162 0 stevel strindex = shdr->sh_link; 163 0 stevel } 164 0 stevel } 165 0 stevel 166 0 stevel for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) { 167 0 stevel if (cnt == strindex) 168 0 stevel strtab = (char *)elf_getdata(scn, NULL)->d_buf; 169 0 stevel } 170 0 stevel 171 0 stevel lastsym = symtab + nsyms; 172 0 stevel nsyms = 0; 173 0 stevel for (symp = symtab; symp < lastsym; symp++) 174 0 stevel if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC && 175 0 stevel symp->st_size != 0) 176 0 stevel add_symbol(symp->st_name + strtab, 177 0 stevel (uintptr_t)symp->st_value, (size_t)symp->st_size); 178 0 stevel 179 0 stevel fake_up_certain_popular_kernel_symbols(); 180 0 stevel (void) sprintf(maxsymname, "0x%lx", ULONG_MAX); 181 0 stevel add_symbol(maxsymname, ULONG_MAX, 1); 182 0 stevel 183 0 stevel qsort(symbol_table, nsyms, sizeof (syment_t), symcmp); 184 0 stevel 185 0 stevel /* 186 0 stevel * Destroy all duplicate symbols, then sort it again. 187 0 stevel */ 188 0 stevel for (i = 0; i < nsyms - 1; i++) 189 0 stevel if (symbol_table[i].addr == symbol_table[i + 1].addr) 190 0 stevel symbol_table[i].addr = 0; 191 0 stevel 192 0 stevel qsort(symbol_table, nsyms, sizeof (syment_t), symcmp); 193 0 stevel 194 0 stevel while (symbol_table[1].addr == 0) { 195 0 stevel symbol_table++; 196 0 stevel nsyms--; 197 0 stevel } 198 0 stevel symbol_table[0].name = "(usermode)"; 199 0 stevel symbol_table[0].addr = 0; 200 0 stevel symbol_table[0].size = 1; 201 0 stevel 202 0 stevel return (0); 203 0 stevel } 204 0 stevel 205 0 stevel char * 206 0 stevel addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep) 207 0 stevel { 208 0 stevel int lo = 0; 209 0 stevel int hi = nsyms - 1; 210 0 stevel int mid; 211 0 stevel syment_t *sep; 212 0 stevel 213 0 stevel while (hi - lo > 1) { 214 0 stevel mid = (lo + hi) / 2; 215 0 stevel if (addr >= symbol_table[mid].addr) { 216 0 stevel lo = mid; 217 0 stevel } else { 218 0 stevel hi = mid; 219 0 stevel } 220 0 stevel } 221 0 stevel sep = &symbol_table[lo]; 222 0 stevel *offset = addr - sep->addr; 223 0 stevel *sizep = sep->size; 224 0 stevel return (sep->name); 225 0 stevel } 226 0 stevel 227 0 stevel uintptr_t 228 0 stevel sym_to_addr(char *name) 229 0 stevel { 230 0 stevel int i; 231 0 stevel syment_t *sep = symbol_table; 232 0 stevel 233 0 stevel for (i = 0; i < nsyms; i++) { 234 0 stevel if (strcmp(name, sep->name) == 0) 235 0 stevel return (sep->addr); 236 0 stevel sep++; 237 0 stevel } 238 0 stevel return (NULL); 239 0 stevel } 240 0 stevel 241 0 stevel size_t 242 0 stevel sym_size(char *name) 243 0 stevel { 244 0 stevel int i; 245 0 stevel syment_t *sep = symbol_table; 246 0 stevel 247 0 stevel for (i = 0; i < nsyms; i++) { 248 0 stevel if (strcmp(name, sep->name) == 0) 249 0 stevel return (sep->size); 250 0 stevel sep++; 251 0 stevel } 252 0 stevel return (0); 253 0 stevel } 254