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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 #include <stdio.h> 26 #include <fcntl.h> 27 #include <link.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <strings.h> 31 #include <sys/regset.h> 32 #include <sys/frame.h> 33 #include <sys/stack.h> 34 #include <signal.h> 35 36 #include "env.h" 37 #include "mach.h" 38 #include "who.h" 39 40 41 static int detail_syms = 0; /* display detail symbol information */ 42 static Objinfo *objhead = NULL; /* head of object list */ 43 static Elist *funclist = NULL; 44 static sigset_t iset; 45 46 static void 47 add_object(Objinfo **objlist, Link_map *lmp) 48 { 49 Objinfo *op, *cur, *prev; 50 Elf_Ehdr *ehdr; 51 Elf_Phdr *phdr; 52 caddr_t lpc, hpc; 53 int i; 54 55 if ((op = calloc(1, sizeof (Objinfo))) == NULL) { 56 (void) fprintf(stderr, "who.so.1: calloc failed\n"); 57 exit(1); 58 } 59 60 lpc = hpc = (caddr_t)lmp->l_addr; 61 /* LINTED */ 62 ehdr = (Elf_Ehdr *)lpc; 63 64 /* LINTED */ 65 for (i = 0, phdr = (Elf_Phdr *)(ehdr->e_phoff + lpc); 66 i < ehdr->e_phnum; i++, phdr++) { 67 caddr_t _hpc; 68 if ((phdr->p_type == PT_LOAD) && 69 ((_hpc = phdr->p_vaddr + phdr->p_memsz + lpc) > hpc)) 70 hpc = _hpc; 71 } 72 op->o_lpc = lpc; 73 op->o_hpc = hpc; 74 op->o_lmp = lmp; 75 76 if (ehdr->e_type == ET_EXEC) 77 op->o_flags |= FLG_OB_FIXED; 78 79 if (*objlist == NULL) { 80 *objlist = op; 81 return; 82 } 83 /* 84 * Do an insertion sort to maintain the list 85 * in order. 86 */ 87 if ((*objlist)->o_lmp->l_addr > lmp->l_addr) { 88 op->o_next = *objlist; 89 *objlist = op; 90 return; 91 } 92 93 for (prev = NULL, cur = *objlist; cur; prev = cur, cur = cur->o_next) { 94 if (lpc < cur->o_lpc) 95 break; 96 } 97 if (prev == NULL) { 98 op->o_next = *objlist; 99 *objlist = op; 100 return; 101 } 102 prev->o_next = op; 103 op->o_next = cur; 104 } 105 106 static void 107 remove_object(Objinfo **objlist, Link_map *lmp) 108 { 109 Objinfo *cur, *prev; 110 111 for (prev = NULL, cur = *objlist; cur; prev = cur, cur = cur->o_next) { 112 if (cur->o_lmp == lmp) 113 break; 114 } 115 116 /* 117 * Did we find it? 118 */ 119 if (!cur) 120 return; 121 122 if (!prev) 123 *objlist = cur->o_next; 124 else 125 prev->o_next = cur->o_next; 126 127 if (cur->o_elf) { 128 (void) elf_end(cur->o_elf); 129 (void) close(cur->o_fd); 130 } 131 free(cur); 132 } 133 134 static void 135 print_simple_address(void *pc) 136 { 137 Dl_info info; 138 139 if (dladdr(pc, &info) == 0) { 140 (void) fprintf(stderr, 141 "\t<unknown>: 0x%lx\n", (unsigned long)pc); 142 return; 143 } 144 145 (void) fprintf(stderr, "\t%s:%s+0x%lx\n", info.dli_fname, 146 info.dli_sname, 147 (ulong_t)((uintptr_t)pc - (uintptr_t)info.dli_saddr)); 148 } 149 150 static void 151 load_syms(Objinfo *op) 152 { 153 int fd; 154 Elf *elf; 155 Elf_Scn *scn; 156 157 if (elf_version(EV_CURRENT) == EV_NONE) { 158 op->o_flags |= FLG_OB_NOSYMS; 159 return; 160 } 161 162 if ((fd = open(op->o_lmp->l_name, O_RDONLY)) == -1) { 163 op->o_flags |= FLG_OB_NOSYMS; 164 return; 165 } 166 167 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { 168 op->o_flags |= FLG_OB_NOSYMS; 169 (void) close(fd); 170 return; 171 } 172 scn = NULL; 173 while ((scn = elf_nextscn(elf, scn)) != NULL) { 174 Elf_Shdr *shdr; 175 Elf_Data *data; 176 177 shdr = elf_getshdr(scn); 178 if (shdr->sh_type != SHT_SYMTAB) 179 continue; 180 data = elf_getdata(scn, 0); 181 op->o_syms = (Elf_Sym *)data->d_buf; 182 /* LINTED */ 183 op->o_symcnt = (uint_t)(shdr->sh_size / shdr->sh_entsize); 184 scn = elf_getscn(elf, shdr->sh_link); 185 data = elf_getdata(scn, 0); 186 op->o_strs = (const char *)data->d_buf; 187 } 188 if (!op->o_syms) { 189 (void) elf_end(elf); 190 (void) close(fd); 191 op->o_flags |= FLG_OB_NOSYMS; 192 } 193 } 194 195 196 static void 197 print_address(caddr_t pc) 198 { 199 Elf_Sym *sym, *_sym; 200 Objinfo *op; 201 int i; 202 203 if (!detail_syms) { 204 print_simple_address(pc); 205 return; 206 } 207 for (op = objhead; op; op = op->o_next) { 208 if ((pc >= op->o_lpc) && (pc <= op->o_hpc)) 209 break; 210 } 211 if (op && (op->o_syms == NULL)) 212 load_syms(op); 213 214 if (!op || (op->o_flags & FLG_OB_NOSYMS)) { 215 print_simple_address(pc); 216 return; 217 } 218 219 sym = op->o_syms; 220 if ((op->o_flags & FLG_OB_FIXED) == 0) 221 pc = (caddr_t)((uintptr_t)pc - (uintptr_t)op->o_lpc); 222 for (i = 0, _sym = op->o_syms; i < op->o_symcnt; i++, _sym++) { 223 if (((uintptr_t)_sym->st_value < (uintptr_t)pc) && 224 (_sym->st_value > sym->st_value)) 225 sym = _sym; 226 } 227 (void) fprintf(stderr, "\t%s:%s+0x%lx\n", op->o_lmp->l_name, 228 sym->st_name + op->o_strs, 229 (ulong_t)((uintptr_t)pc - (uintptr_t)sym->st_value)); 230 } 231 232 static void 233 print_stack(struct frame *sp) 234 { 235 FLUSHWIN(); 236 237 while (sp && sp->fr_savpc) { 238 print_address((caddr_t)sp->fr_savpc); 239 sp = (struct frame *)((ulong_t)sp->fr_savfp + STACK_BIAS); 240 } 241 } 242 243 uint_t 244 la_version(uint_t version) 245 { 246 if (version > LAV_CURRENT) 247 (void) fprintf(stderr, "who.so: unexpected version: %d\n", 248 version); 249 250 if (checkenv((const char *)"WHO_DETAIL")) 251 detail_syms++; 252 253 build_env_list(&funclist, (const char *)"WHOCALLS"); 254 255 /* 256 * Initalize iset to the full set of signals to be masked durring 257 * pltenter/pltexit 258 */ 259 (void) sigfillset(&iset); 260 261 return (LAV_CURRENT); 262 } 263 264 /* ARGSUSED1 */ 265 uint_t 266 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 267 { 268 add_object(&objhead, lmp); 269 return (LA_FLG_BINDTO | LA_FLG_BINDFROM); 270 } 271 272 uint_t 273 la_objclose(uintptr_t *cookie) 274 { 275 remove_object(&objhead, (Link_map *)(*cookie)); 276 return (1); 277 } 278 279 /* ARGSUSED1 */ 280 #if defined(__sparcv9) 281 uintptr_t 282 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 283 uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, 284 const char *sym_name) 285 #elif defined(__sparc) 286 uintptr_t 287 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 288 uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) 289 #elif defined(__amd64) 290 uintptr_t 291 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 292 uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, 293 const char *sym_name) 294 #elif defined(__i386) 295 uintptr_t 296 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, 297 uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) 298 #endif 299 { 300 sigset_t oset; 301 #if !defined(_LP64) 302 const char *sym_name = (const char *)symp->st_name; 303 #endif 304 305 (void) sigprocmask(SIG_BLOCK, &iset, &oset); 306 if (check_list(funclist, sym_name)) { 307 struct frame *frame_p; 308 309 (void) fprintf(stderr, "%s(0x%lx, 0x%lx, 0x%lx)\n", sym_name, 310 (long)GETARG0(regset), (long)GETARG1(regset), 311 (long)GETARG2(regset)); 312 313 print_address((caddr_t)GETPREVPC(regset)); 314 315 frame_p = (struct frame *)((ulong_t)GETFRAME(regset) 316 + STACK_BIAS); 317 318 print_stack(frame_p); 319 (void) fflush(stdout); 320 } 321 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 322 return (symp->st_value); 323 } 324