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