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.
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.
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]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
31 #include <sys/regset.h>
32 #include <sys/frame.h>
33 #include <sys/stack.h>
41 static int detail_syms
= 0; /* display detail symbol information */
42 static Objinfo
*objhead
= NULL
; /* head of object list */
43 static Elist
*funclist
= NULL
;
47 add_object(Objinfo
**objlist
, Link_map
*lmp
)
49 Objinfo
*op
, *cur
, *prev
;
55 if ((op
= calloc(1, sizeof (Objinfo
))) == NULL
) {
56 (void) fprintf(stderr
, "who.so.1: calloc failed\n");
60 lpc
= hpc
= (caddr_t
)lmp
->l_addr
;
62 ehdr
= (Elf_Ehdr
*)lpc
;
65 for (i
= 0, phdr
= (Elf_Phdr
*)(ehdr
->e_phoff
+ lpc
);
66 i
< ehdr
->e_phnum
; i
++, phdr
++) {
68 if ((phdr
->p_type
== PT_LOAD
) &&
69 ((_hpc
= phdr
->p_vaddr
+ phdr
->p_memsz
+ lpc
) > hpc
))
76 if (ehdr
->e_type
== ET_EXEC
)
77 op
->o_flags
|= FLG_OB_FIXED
;
79 if (*objlist
== NULL
) {
84 * Do an insertion sort to maintain the list
87 if ((*objlist
)->o_lmp
->l_addr
> lmp
->l_addr
) {
88 op
->o_next
= *objlist
;
93 for (prev
= NULL
, cur
= *objlist
; cur
; prev
= cur
, cur
= cur
->o_next
) {
98 op
->o_next
= *objlist
;
107 remove_object(Objinfo
**objlist
, Link_map
*lmp
)
111 for (prev
= NULL
, cur
= *objlist
; cur
; prev
= cur
, cur
= cur
->o_next
) {
112 if (cur
->o_lmp
== lmp
)
123 *objlist
= cur
->o_next
;
125 prev
->o_next
= cur
->o_next
;
128 (void) elf_end(cur
->o_elf
);
129 (void) close(cur
->o_fd
);
135 print_simple_address(void *pc
)
139 if (dladdr(pc
, &info
) == 0) {
140 (void) fprintf(stderr
,
141 "\t<unknown>: 0x%lx\n", (unsigned long)pc
);
145 (void) fprintf(stderr
, "\t%s:%s+0x%lx\n", info
.dli_fname
,
147 (ulong_t
)((uintptr_t)pc
- (uintptr_t)info
.dli_saddr
));
151 load_syms(Objinfo
*op
)
157 if (elf_version(EV_CURRENT
) == EV_NONE
) {
158 op
->o_flags
|= FLG_OB_NOSYMS
;
162 if ((fd
= open(op
->o_lmp
->l_name
, O_RDONLY
)) == -1) {
163 op
->o_flags
|= FLG_OB_NOSYMS
;
167 if ((elf
= elf_begin(fd
, ELF_C_READ
, 0)) == NULL
) {
168 op
->o_flags
|= FLG_OB_NOSYMS
;
173 while ((scn
= elf_nextscn(elf
, scn
)) != NULL
) {
177 shdr
= elf_getshdr(scn
);
178 if (shdr
->sh_type
!= SHT_SYMTAB
)
180 data
= elf_getdata(scn
, 0);
181 op
->o_syms
= (Elf_Sym
*)data
->d_buf
;
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
;
191 op
->o_flags
|= FLG_OB_NOSYMS
;
197 print_address(caddr_t pc
)
204 print_simple_address(pc
);
207 for (op
= objhead
; op
; op
= op
->o_next
) {
208 if ((pc
>= op
->o_lpc
) && (pc
<= op
->o_hpc
))
211 if (op
&& (op
->o_syms
== NULL
))
214 if (!op
|| (op
->o_flags
& FLG_OB_NOSYMS
)) {
215 print_simple_address(pc
);
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
))
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
));
233 print_stack(struct frame
*sp
)
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
);
244 la_version(uint_t version
)
246 if (version
> LAV_CURRENT
)
247 (void) fprintf(stderr
, "who.so: unexpected version: %d\n",
250 if (checkenv((const char *)"WHO_DETAIL"))
253 build_env_list(&funclist
, (const char *)"WHOCALLS");
256 * Initalize iset to the full set of signals to be masked durring
259 (void) sigfillset(&iset
);
261 return (LAV_CURRENT
);
266 la_objopen(Link_map
*lmp
, Lmid_t lmid
, uintptr_t *cookie
)
268 add_object(&objhead
, lmp
);
269 return (LA_FLG_BINDTO
| LA_FLG_BINDFROM
);
273 la_objclose(uintptr_t *cookie
)
275 remove_object(&objhead
, (Link_map
*)(*cookie
));
280 #if defined(__sparcv9)
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)
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)
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)
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
)
302 const char *sym_name
= (const char *)symp
->st_name
;
305 (void) sigprocmask(SIG_BLOCK
, &iset
, &oset
);
306 if (check_list(funclist
, sym_name
)) {
307 struct frame
*frame_p
;
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
));
313 print_address((caddr_t
)GETPREVPC(regset
));
315 frame_p
= (struct frame
*)((ulong_t
)GETFRAME(regset
)
318 print_stack(frame_p
);
319 (void) fflush(stdout
);
321 (void) sigprocmask(SIG_SETMASK
, &oset
, NULL
);
322 return (symp
->st_value
);