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 #include <sys/machelf.h> 46 47 #include <kstat.h> 48 #include <sys/cpuvar.h> 49 50 typedef struct syment { 51 uintptr_t addr; 52 char *name; 53 size_t size; 54 } syment_t; 55 56 static syment_t *symbol_table; 57 static int nsyms, maxsyms; 58 static char maxsymname[64]; 59 60 #ifdef _ELF64 61 #define elf_getshdr elf64_getshdr 62 #else 63 #define elf_getshdr elf32_getshdr 64 #endif 65 66 static void 67 add_symbol(char *name, uintptr_t addr, size_t size) 68 { 69 syment_t *sep; 70 71 if (nsyms >= maxsyms) { 72 maxsyms += 10000; 73 symbol_table = realloc(symbol_table, maxsyms * sizeof (*sep)); 74 if (symbol_table == NULL) { 75 (void) fprintf(stderr, "can't allocate symbol table\n"); 76 exit(3); 77 } 78 } 79 sep = &symbol_table[nsyms++]; 80 81 sep->name = name; 82 sep->addr = addr; 83 sep->size = size; 84 } 85 86 static void 87 remove_symbol(uintptr_t addr) 88 { 89 int i; 90 syment_t *sep = symbol_table; 91 92 for (i = 0; i < nsyms; i++, sep++) 93 if (sep->addr == addr) 94 sep->addr = 0; 95 } 96 97 static void 98 fake_up_certain_popular_kernel_symbols(void) 99 { 100 kstat_ctl_t *kc; 101 kstat_t *ksp; 102 char *name; 103 104 if ((kc = kstat_open()) == NULL) 105 return; 106 107 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 108 if (strcmp(ksp->ks_module, "cpu_info") == 0) { 109 if ((name = malloc(20)) == NULL) 110 break; 111 /* 112 * For consistency, keep cpu[0] and toss cpu0 113 * or any other such symbols. 114 */ 115 if (ksp->ks_instance == 0) 116 remove_symbol((uintptr_t)ksp->ks_private); 117 (void) sprintf(name, "cpu[%d]", ksp->ks_instance); 118 add_symbol(name, (uintptr_t)ksp->ks_private, 119 sizeof (struct cpu)); 120 } 121 } 122 (void) kstat_close(kc); 123 } 124 125 static int 126 symcmp(const void *p1, const void *p2) 127 { 128 uintptr_t a1 = ((syment_t *)p1)->addr; 129 uintptr_t a2 = ((syment_t *)p2)->addr; 130 131 if (a1 < a2) 132 return (-1); 133 if (a1 > a2) 134 return (1); 135 return (0); 136 } 137 138 int 139 symtab_init(void) 140 { 141 Elf *elf; 142 Elf_Scn *scn = NULL; 143 Sym *symtab, *symp, *lastsym; 144 char *strtab; 145 uint_t cnt; 146 int fd; 147 int i; 148 int strindex = -1; 149 150 if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) 151 return (-1); 152 153 (void) elf_version(EV_CURRENT); 154 155 elf = elf_begin(fd, ELF_C_READ, NULL); 156 157 for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) { 158 Shdr *shdr = elf_getshdr(scn); 159 if (shdr->sh_type == SHT_SYMTAB) { 160 symtab = (Sym *)elf_getdata(scn, NULL)->d_buf; 161 nsyms = shdr->sh_size / shdr->sh_entsize; 162 strindex = shdr->sh_link; 163 } 164 } 165 166 for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) { 167 if (cnt == strindex) 168 strtab = (char *)elf_getdata(scn, NULL)->d_buf; 169 } 170 171 lastsym = symtab + nsyms; 172 nsyms = 0; 173 for (symp = symtab; symp < lastsym; symp++) 174 if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC && 175 symp->st_size != 0) 176 add_symbol(symp->st_name + strtab, 177 (uintptr_t)symp->st_value, (size_t)symp->st_size); 178 179 fake_up_certain_popular_kernel_symbols(); 180 (void) sprintf(maxsymname, "0x%lx", ULONG_MAX); 181 add_symbol(maxsymname, ULONG_MAX, 1); 182 183 qsort(symbol_table, nsyms, sizeof (syment_t), symcmp); 184 185 /* 186 * Destroy all duplicate symbols, then sort it again. 187 */ 188 for (i = 0; i < nsyms - 1; i++) 189 if (symbol_table[i].addr == symbol_table[i + 1].addr) 190 symbol_table[i].addr = 0; 191 192 qsort(symbol_table, nsyms, sizeof (syment_t), symcmp); 193 194 while (symbol_table[1].addr == 0) { 195 symbol_table++; 196 nsyms--; 197 } 198 symbol_table[0].name = "(usermode)"; 199 symbol_table[0].addr = 0; 200 symbol_table[0].size = 1; 201 202 return (0); 203 } 204 205 char * 206 addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep) 207 { 208 int lo = 0; 209 int hi = nsyms - 1; 210 int mid; 211 syment_t *sep; 212 213 while (hi - lo > 1) { 214 mid = (lo + hi) / 2; 215 if (addr >= symbol_table[mid].addr) { 216 lo = mid; 217 } else { 218 hi = mid; 219 } 220 } 221 sep = &symbol_table[lo]; 222 *offset = addr - sep->addr; 223 *sizep = sep->size; 224 return (sep->name); 225 } 226 227 uintptr_t 228 sym_to_addr(char *name) 229 { 230 int i; 231 syment_t *sep = symbol_table; 232 233 for (i = 0; i < nsyms; i++) { 234 if (strcmp(name, sep->name) == 0) 235 return (sep->addr); 236 sep++; 237 } 238 return (NULL); 239 } 240 241 size_t 242 sym_size(char *name) 243 { 244 int i; 245 syment_t *sep = symbol_table; 246 247 for (i = 0; i < nsyms; i++) { 248 if (strcmp(name, sep->name) == 0) 249 return (sep->size); 250 sep++; 251 } 252 return (0); 253 } 254