# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../../../Makefile.master ROOTDEMODIRBASE= $(ROOT)/usr/demo/link_audit DEMOFILES= \ 00README \ Makefile \ man/perfcnt.man \ man/symbindrep.man \ man/dumpbind.man \ src/bindings.c \ src/bindings.h \ src/dumpbind.c \ src/env.c \ src/env.h \ src/hash.c \ src/hash.h \ src/sotruss.ksh \ src/mach.h \ src/perfcnt.c \ src/perfcnt.ksh \ src/symbindrep.c \ src/symbindrep.ksh \ src/truss.c \ src/who.c \ src/who.h \ src/whocalls.ksh ROOTDEMODIRS= $(ROOTDEMODIRBASE) .WAIT \ $(ROOTDEMODIRBASE)/man \ $(ROOTDEMODIRBASE)/src ROOTDEMOFILES= $(DEMOFILES:%=$(ROOTDEMODIRBASE)/%) $(ROOTDEMODIRS) : DIRMODE = 755 # Hammerhead: amd64-only SUBDIRS= $(MACH64) all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber .PARALLEL: $(ROOTDEMOFILES) .KEEP_STATE: all clean clobber: $(SUBDIRS) install: $(ROOTDEMODIRS) .WAIT $(SUBDIRS) $(ROOTDEMOFILES) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) @if [ -d $(MACH64) ]; then \ cd $(MACH64); pwd; $(MAKE) $(TARGET); \ else /bin/true; fi $(ROOTDEMODIRS): $(INS.dir) $(ROOTDEMODIRBASE)/man/%: man/% $(INS.file) $(ROOTDEMODIRBASE)/src/%: common/% $(INS.file) $(ROOTDEMODIRBASE)/%: common/% $(INS.file) $(ROOTDEMODIRBASE)/%: common/%.demo $(INS.rename) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../../../../lib/Makefile.lib include ../../Makefile.com TRUSSLIB= truss.so.1 TRUSSSRC= truss.c SYMBINDREP= symbindrep.so.1 SYMBINDREPSRC= symbindrep.c PERFLIB= perfcnt.so.1 PERFSRC= perfcnt.c hash.c WHOLIB= who.so.1 WHOSRC= who.c BINDLIB= bindings.so.1 BINDSRC= bindings.c ONSCRIPTS= perfcnt symbindrep ONPROGS= dumpbind ONLIBS= $(SYMBINDREP) $(PERFLIB) $(BINDLIB) USRSCRIPTS= sotruss whocalls CCSLIBS= $(TRUSSLIB) $(WHOLIB) PICDIR= pics OBJDIR= objs TRUSSPICS= $(TRUSSSRC:%.c=$(PICDIR)/%.o) $(PICDIR)/env.o PERFPICS= $(PERFSRC:%.c=$(PICDIR)/%.o) $(PICDIR)/env.o WHOPICS= $(WHOSRC:%.c=$(PICDIR)/%.o) $(PICDIR)/env.o SYMBINDREPPICS= $(SYMBINDREPSRC:%.c=$(PICDIR)/%.o) $(PICDIR)/env.o BINDPICS= $(BINDSRC:%.c=$(PICDIR)/%.o) $(PICDIR)/env.o $(WHOPICS): SEMANTICCHK= LDLIBS += $(CONVLIBDIR) -lconv $(TRUSSLIB): PICS = $(TRUSSPICS) $(PERFLIB): PICS = $(PERFPICS) $(WHOLIB): PICS = $(WHOPICS) $(SYMBINDREP): PICS = $(SYMBINDREPPICS) $(BINDLIB): PICS = $(BINDPICS) $(TRUSSLIB): LDLIBS += $(ZRECORD) -lmapmalloc -lc $(PERFLIB): LDLIBS += $(ZRECORD) -lmapmalloc -lc $(WHOLIB): LDLIBS += $(ELFLIBDIR) -lelf $(ZRECORD) -lmapmalloc $(DLLIB) -lc $(SYMBINDREP): LDLIBS += $(ZRECORD) -lmapmalloc -lc $(BINDLIB): LDLIBS += $(ZRECORD) -lmapmalloc -lc $(TRUSSLIB): SONAME = $(TRUSSLIB) $(PERFLIB): SONAME = $(PERFLIB) $(WHOLIB): SONAME = $(WHOLIB) $(SYMBINDREP): SONAME = $(SYMBINDREP) $(BINDLIB): SONAME = $(BINDLIB) $(TRUSSLIB): MAPFILES = ../common/mapfile-vers-truss $(PERFLIB): MAPFILES = ../common/mapfile-vers-perfcnt $(WHOLIB): MAPFILES = ../common/mapfile-vers-who $(SYMBINDREP): MAPFILES = ../common/mapfile-vers-symbindrep $(BINDLIB): MAPFILES = ../common/mapfile-vers-bindings $(ONPROGS): LDFLAGS += $(LDLIBS.cmd) $(BDIRECT) $(ROOTCCSLIB) : DIRMODE = 755 CPPFLAGS += -D_REENTRANT DYNFLAGS += $(VERSREF) CLEANFILES += $(OBJDIR)/* $(PICDIR)/* CLOBBERFILES += $(ONSCRIPTS) $(ONPROGS) $(ONLIBS) $(CCSLIBS) $(USRSCRIPTS) ROOTONLDLIB= $(ROOT)/opt/SUNWonld/lib ROOTONLDLIBS= $(ONLIBS:%=$(ROOTONLDLIB)/%) ROOTONLDLIB64= $(ROOTONLDLIB)/$(MACH64) ROOTONLDLIBS64= $(ONLIBS:%=$(ROOTONLDLIB64)/%) ROOTONLDBIN= $(ROOT)/opt/SUNWonld/bin ROOTONLDBINPROG= $(ONSCRIPTS:%=$(ROOTONLDBIN)/%) \ $(ONPROGS:%=$(ROOTONLDBIN)/%) ROOTCCSLIB= $(ROOT)/usr/lib/link_audit ROOTCCSLIB64= $(ROOT)/usr/lib/link_audit/$(MACH64) ROOTCCSLIBS= $(CCSLIBS:%=$(ROOTCCSLIB)/%) ROOTCCSLIBS64= $(CCSLIBS:%=$(ROOTCCSLIB64)/%) ROOTUSRBIN= $(ROOT)/usr/bin ROOTUSRBINS= $(USRSCRIPTS:%=$(ROOTUSRBIN)/%) FILEMODE= 0755 .PARALLEL: $(LIBS) $(PROGS) $(SCRIPTS) $(TRUSSPICS) $(PERFPICS) \ $(WHOPICS) $(SYMBINDREPPICS) $(BINDPICS) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2015 RackTop Systems. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # %: ../common/%.ksh $(RM) $@ cat $< > $@ chmod +x $@ $(PICDIR)/%.o: %.c $(COMPILE.c) $< -o $@ $(POST_PROCESS_O) $(PICDIR)/%.o: ../common/%.c $(COMPILE.c) $< -o $@ $(POST_PROCESS_O) $(OBJDIR)/%.o: %.c $(COMPILE.c) $< -o $@ $(POST_PROCESS_O) $(OBJDIR)/%.o: ../common/%.c $(COMPILE.c) $< -o $@ $(POST_PROCESS_O) $(TRUSSLIB): $(TRUSSPICS) $(BUILD.SO) $(POST_PROCESS_SO) $(BINDLIB): $(BINDPICS) $(BUILD.SO) $(POST_PROCESS_SO) $(SYMBINDREP): $(SYMBINDREPPICS) $(BUILD.SO) $(POST_PROCESS_SO) $(PERFLIB): $(PERFPICS) $(BUILD.SO) $(POST_PROCESS_SO) $(WHOLIB): $(WHOPICS) $(BUILD.SO) $(POST_PROCESS_SO) dumpbind: $(OBJDIR)/dumpbind.o $(LINK.c) -o $@ $(OBJDIR)/dumpbind.o $(LDLIBS) $(POST_PROCESS) $(ROOTUSRBIN)/%: % $(INS.file) $(ROOTCCSLIB)/%: % $(INS.file) $(ROOTCCSLIB64)/%: % $(INS.file) $(ROOTONLDBIN)/%: % $(ROOTONLDBIN) $(INS.file) $(ROOTONLDLIB)/%: % $(ROOTONLDLIB) $(INS.file) $(ROOTONLDLIB64)/%: % $(ROOTONLDLIB64) $(INS.file) $(ROOTCCSLIB): $(INS.dir) $(ROOTCCSLIB64): $(INS.dir) $(ROOTONLDBIN): $(INS.dir) $(ROOTONLDLIB): $(INS.dir) $(ROOTONLDLIB64): $(INS.dir) include ../../../../lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../Makefile.com CONVLIBDIR = $(CONVLIBDIR64) ELFLIBDIR = $(ELFLIBDIR64) $(ONLIBS) \ $(CCSLIBS) : CFLAGS64 += $(C_PICFLAGS64) $(NO_ASM_WARN) .KEEP_STATE: all: $(PICDIR) .WAIT $(CCSLIBS) $(CCSSCRIPTS) \ $(ONSCRIPTS) $(ONLIBS) install: all $(ROOTCCSLIB64) .WAIT $(ROOTCCSLIBS64) .WAIT $(ROOTONLDLIBS64) include ../Makefile.targ include $(SRC)/Makefile.master.64 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. # This directory contains sample code on how to use the Link-Auditing interface of the runtime linker (ld.so.1(1)). The Link-Auditing interface permits a user supplied shared object to audit objects that are loaded, and symbols that are bound, by the runtime linker. A full description of the Link-Auditing interface can be found in the "Linker & Libraries Guide", which is part of the "Software Developer Collection". The following is an overview of the directory structure and highlights some of the important files contained within: Makefile - Makefile to build the Link-Auditing examples src/* - source code man/* - Man pages for the examples Building the demos ------------------ % make all # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2015 RackTop Systems. # MACH = $(shell uname -p) sparc_XARCH= sparc64_XARCH= -m64 i386_XARCH= i38664_XARCH= -m64 C_PICFLAGS= -Kpic C_PICFLAGS64= -Kpic PROGS= dumpbind LIBS= truss.so.1 symbindrep.so.1 perfcnt.so.1 who.so.1 bindings.so.1 KSHSRC= sotruss.ksh symbindrep.ksh perfcnt.ksh whocalls.ksh SCRIPTS= $(KSHSRC:%.ksh=%) DIRS= obj32 obj64 lib32 lib64 sparc_LIBS32= $(LIBS:%=lib32/%) sparc_LIBS64= $(LIBS:%=lib64/%) i386_LIBS32= $(LIBS:%=lib32/%) i386_LIBS64= $(LIBS:%=lib64/%) LIBS64= $($(MACH)_LIBS64) LIBS32= $($(MACH)_LIBS32) ALLIBS= $(LIBS32) $(LIBS64) $(LIBS32): CFLAGS += $($(MACH)_XARCH) $(C_PICFLAGS) $(LIBS32): LDLIBS += -lmapmalloc -ldl -lc $(LIBS64): CFLAGS += $($(MACH)64_XARCH) $(C_PICFLAGS64) $(LIBS64): LDLIBS += -lmapmalloc -ldl -lc CPPFLAGS += -Isrc -D__EXTENSIONS__ LDFLAGS = $(ZDEFS) $(ZTEXT) $(ZIGNORE) .KEEP_STATE: all: $(DIRS) .WAIT $(ALLIBS) $(SCRIPTS) $(PROGS) %: src/%.ksh $(RM) $@ cat $< | sed -e s,/opt/SUNWonld/lib/,`pwd`/lib, | \ sed -e s,/usr/lib/link_audit/,`pwd`/lib, > $@ chmod a+x $@ obj32/%.o \ obj64/%.o: src/%.c $(COMPILE.c) $< -o $@ dumpbind: \ obj32/dumpbind.o $(LINK.c) obj32/dumpbind.o -o $@ $(LDLIBS) lib32/bindings.so.1: \ obj32/bindings.o obj32/env.o $(LINK.c) -G obj32/bindings.o obj32/env.o -o $@ $(LDLIBS) lib64/bindings.so.1: \ obj64/bindings.o obj64/env.o $(LINK.c) -G obj64/bindings.o obj64/env.o -o $@ $(LDLIBS) lib32/perfcnt.so.1: \ obj32/perfcnt.o obj32/hash.o obj32/env.o $(LINK.c) -G obj32/perfcnt.o obj32/hash.o obj32/env.o -o $@ $(LDLIBS) lib64/perfcnt.so.1: \ obj64/perfcnt.o obj64/hash.o obj64/env.o $(LINK.c) -G obj64/perfcnt.o obj64/hash.o obj64/env.o -o $@ $(LDLIBS) lib32/symbindrep.so.1: \ obj32/symbindrep.o obj32/env.o $(LINK.c) -G obj32/symbindrep.o obj32/env.o -o $@ $(LDLIBS) lib64/symbindrep.so.1: \ obj64/symbindrep.o obj64/env.o $(LINK.c) -G obj64/symbindrep.o obj64/env.o -o $@ $(LDLIBS) lib32/truss.so.1: \ obj32/truss.o obj32/env.o $(LINK.c) -G obj32/truss.o obj32/env.o -o $@ $(LDLIBS) lib64/truss.so.1: \ obj64/truss.o obj64/env.o $(LINK.c) -G obj64/truss.o obj64/env.o -o $@ $(LDLIBS) lib32/who.so.1: \ obj32/who.o obj32/env.o $(LINK.c) -G obj32/who.o obj32/env.o -o $@ -lelf $(LDLIBS) lib64/who.so.1: \ obj64/who.o obj64/env.o $(LINK.c) -G obj64/who.o obj64/env.o -o $@ -lelf $(LDLIBS) obj32 \ obj64 \ lib32 \ lib64: @mkdir $@ | cat clean \ clobber:FRC $(RM) -r $(DIRS) $(SCRIPTS) $(PROGS) core .make.state FRC: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bindings.h" #include "env.h" static Elist *bindto_list = NULL; static Elist *bindfrom_list = NULL; static bindhead *bhp = NULL; static unsigned int current_map_len = 0; static char *buffer_name; static const sigset_t iset = { ~0U, ~0U, ~0U, ~0U }; static lwp_mutex_t sharedmutex = SHAREDMUTEX; /* * This routine was stolen from libelf.so.1 */ static unsigned long ehash(const char *name) { unsigned int g, h = 0; const unsigned char *nm = (unsigned char *)name; while (*nm != '\0') { h = (h << 4) + *nm++; /* LINTED */ if ((g = (unsigned int)(h & MASK)) != 0) h ^= g >> 24; h &= ~MASK; } return ((unsigned long)h); } static void output_err_message(const char *msg) { int fd; if ((fd = open("/tmp/bind_err", O_RDWR | O_CREAT, 0666)) == -1) { (void) fprintf(stderr, "bindings.so: unable to open err_log\n"); perror("open"); } (void) lseek(fd, 0, SEEK_END); (void) write(fd, msg, strlen(msg)); (void) close(fd); } /* * common mutex locking & unlocking routines for this module. This is to * control the setting of 'lock_held'. */ static void bt_lock(lwp_mutex_t *lock) { if (_lwp_mutex_lock(lock) != 0) { output_err_message("bt_lock failed!!\n"); (void) fprintf(stderr, "bindings.so: unable to obtain lock\n"); perror("_lwp_mutex_lock"); } } static void bt_unlock(lwp_mutex_t *lock) { if (_lwp_mutex_unlock(lock) != 0) { output_err_message("bt_unlock failed!!\n"); (void) fprintf(stderr, "bindings.so: unable to unlock lock\n"); perror("_lwp_mutex_unlock"); } } /* * It's always possible that another process sharing our buffer * has caused it to grow. If this is the case we must adjust our * mappings to compensate. */ static void remap_buffer(int fd) { void * new_bhp; if ((new_bhp = mmap(0, bhp->bh_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { (void) fprintf(stderr, "bindings: remap: mmap failed\n"); perror("mmap"); bt_unlock(&bhp->bh_lock); exit(1); } /* * clean up old mapping */ (void) munmap((caddr_t)bhp, current_map_len); bhp = (bindhead *)new_bhp; current_map_len = bhp->bh_size; } static void grow_buffer(void) { int fd; if ((fd = open(buffer_name, O_RDWR)) == -1) { (void) fprintf(stderr, "bidings: grow_buffer: open failed: %s\n", buffer_name); perror("open"); bt_unlock(&bhp->bh_lock); exit(1); } if (ftruncate(fd, bhp->bh_size + BLKSIZE) == -1) { (void) fprintf(stderr, "grow_buffer failed\n"); perror("ftruncate"); bt_unlock(&bhp->bh_lock); exit(1); } bhp->bh_size += BLKSIZE; remap_buffer(fd); (void) close(fd); } static void get_new_strbuf(void) { bt_lock(&bhp->bh_lock); while (bhp->bh_end + STRBLKSIZE > bhp->bh_size) grow_buffer(); bhp->bh_strcur = bhp->bh_end; bhp->bh_end = bhp->bh_strend = bhp->bh_strcur + STRBLKSIZE; bt_unlock(&bhp->bh_lock); } static unsigned int save_str(const char *str) { char *sptr; unsigned int bptr; unsigned int slen; bt_lock(&bhp->bh_strlock); /* LINTED */ slen = (unsigned int)strlen(str); /* * will string fit into our current string buffer? */ if ((slen + 1) > (bhp->bh_strend - bhp->bh_strcur)) get_new_strbuf(); bptr = bhp->bh_strcur; sptr = (char *)bhp + bhp->bh_strcur; bhp->bh_strcur += slen + 1; (void) strncpy(sptr, str, slen); sptr[slen] = '\0'; bt_unlock(&bhp->bh_strlock); return (bptr); } static unsigned int get_new_entry(void) { unsigned int new_ent; bt_lock(&bhp->bh_lock); while ((sizeof (binding_entry) + bhp->bh_end) > bhp->bh_size) grow_buffer(); new_ent = bhp->bh_end; bhp->bh_end += sizeof (binding_entry); bt_unlock(&bhp->bh_lock); return (new_ent); } static void init_locks(void) { int i; (void) memcpy(&bhp->bh_lock, &sharedmutex, sizeof (lwp_mutex_t)); for (i = 0; i < DEFBKTS; i++) (void) memcpy(&bhp->bh_bkts[i].bb_lock, &sharedmutex, sizeof (lwp_mutex_t)); (void) memcpy(&bhp->bh_strlock, &sharedmutex, sizeof (lwp_mutex_t)); } uint_t la_version(uint_t version) { int fd; sigset_t omask; if (version < LAV_CURRENT) { (void) fprintf(stderr, "bindings.so: unexpected link_audit version: %d\n", version); return (0); } build_env_list(&bindto_list, (const char *)"BT_BINDTO"); build_env_list(&bindfrom_list, (const char *)"BT_BINDFROM"); if ((buffer_name = getenv(FILEENV)) == NULL) buffer_name = DEFFILE; (void) sigprocmask(SIG_BLOCK, &iset, &omask); if ((fd = open(buffer_name, O_RDWR | O_CREAT | O_EXCL, 0666)) != -1) { int init_size = sizeof (bindhead) + BLKSIZE; if (ftruncate(fd, init_size) == -1) { perror("ftruncate"); return (0); } /* LINTED */ if ((bhp = (bindhead *)mmap(0, init_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { perror("bindings.so: mmap"); return (0); } (void) close(fd); init_locks(); /* * Lock our structure and then initialize the data */ bt_lock(&bhp->bh_lock); bhp->bh_vers = BINDCURVERS; current_map_len = bhp->bh_size = init_size; bhp->bh_end = sizeof (bindhead); bhp->bh_bktcnt = DEFBKTS; bt_unlock(&bhp->bh_lock); /* * Set up our initial string buffer */ get_new_strbuf(); } else if ((fd = open(buffer_name, O_RDWR)) != -1) { struct stat stbuf; int i; for (i = 0; i < 4; i++) { if (fstat(fd, &stbuf) == -1) { (void) sleep(1); continue; } if (stbuf.st_size < sizeof (bindhead)) { (void) sleep(1); continue; } /* LINTED */ if ((bhp = (bindhead *)mmap(0, stbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { (void) fprintf(stderr, "bindings: mmap failed\n"); perror("mmap"); return (0); } /* LINTED */ current_map_len = (unsigned int)stbuf.st_size; } if (bhp == NULL) { (void) fprintf(stderr, "bindings: buffer mapping timed out\n"); return (0); } for (i = 0; i < 4; i++) { if (bhp->bh_vers == 0) { (void) sleep(1); continue; } } if (bhp->bh_vers == 0) { (void) fprintf(stderr, "bindings: %s not initialized\n", buffer_name); return (0); } bt_lock(&bhp->bh_lock); if (bhp->bh_size != current_map_len) remap_buffer(fd); (void) close(fd); } else { (void) fprintf(stderr, "bindings: unable to open %s\n", buffer_name); perror("open"); return (0); } (void) sigprocmask(SIG_SETMASK, &omask, NULL); bt_unlock(&bhp->bh_lock); return (LAV_CURRENT); } /* ARGSUSED 0 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { uint_t flags; if ((bindto_list == NULL) || (check_list(bindto_list, lmp->l_name))) flags = LA_FLG_BINDTO; else flags = 0; if ((bindfrom_list == NULL) || (check_list(bindfrom_list, lmp->l_name))) flags |= LA_FLG_BINDFROM; return (flags); } /* ARGSUSED 1 */ #if defined(__sparcv9) uintptr_t la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_sparcv9_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__sparc) uintptr_t la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_sparcv8_regs *regset, uint_t *sb_flags) #elif defined(__amd64) uintptr_t la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_amd64_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__i386) uintptr_t la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) #endif { unsigned long bktno; Link_map *dlmp = (Link_map *)*defcook; const char *lib_name; sigset_t omask; #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif lib_name = dlmp->l_name; (void) sigprocmask(SIG_BLOCK, &iset, &omask); if (sym_name == NULL) { output_err_message("null symname\n"); return (symp->st_value); } bktno = ehash(sym_name) % bhp->bh_bktcnt; bt_lock(&bhp->bh_bkts[bktno].bb_lock); /* * The buffer has been grown (by another process) and * we need to remap it into memory. */ if (bhp->bh_size != current_map_len) { int fd; if ((fd = open(buffer_name, O_RDWR)) == -1) { (void) fprintf(stderr, "bidings: plt_enter: open failed: %s\n", buffer_name); perror("open"); bt_unlock(&bhp->bh_lock); exit(1); } bt_lock(&bhp->bh_lock); remap_buffer(fd); bt_unlock(&bhp->bh_lock); (void) close(fd); } if (bhp->bh_bkts[bktno].bb_head == 0) { binding_entry * bep; unsigned int be_off; unsigned int sym_off; unsigned int lib_off; be_off = get_new_entry(); sym_off = save_str(sym_name); lib_off = save_str(lib_name); /* LINTED */ bep = (binding_entry *)((char *)bhp + be_off); bep->be_next = 0; bep->be_sym_name = sym_off; bep->be_lib_name = lib_off; bep->be_count = 1; bhp->bh_bkts[bktno].bb_head = be_off; } else { int strcmp_res; unsigned int prev_off = 0; binding_entry *prev_bep = NULL; unsigned int cur_off; binding_entry *cur_bep; unsigned int lib_off = 0; /* * Once we get to the bucket, we do a two tiered * search. First we search for a library match, then * we search for a symbol match. */ cur_off = bhp->bh_bkts[bktno].bb_head; /* LINTED */ cur_bep = (binding_entry *)((char *)bhp + cur_off); while (cur_off && (strcmp_res = strcmp((char *)bhp + cur_bep->be_lib_name, lib_name)) < 0) { prev_off = cur_off; cur_off = cur_bep->be_next; /* LINTED */ cur_bep = (binding_entry *)((char *)bhp + cur_off); } if (cur_off && (strcmp_res == 0)) { /* * This is a small optimization. For * each bucket we will only record a library * name once. Once it has been recorded in * a bucket we will just re-use the same * string. */ lib_off = cur_bep->be_lib_name; while (cur_off && (strcmp_res = strcmp((char *)bhp + cur_bep->be_sym_name, sym_name)) < 0) { prev_off = cur_off; cur_off = cur_bep->be_next; /* LINTED */ cur_bep = (binding_entry *)((char *)bhp + cur_off); } } if (strcmp_res == 0) { /* * We've got a match */ cur_bep->be_count++; } else { unsigned int new_off; binding_entry * new_bep; unsigned int sym_off; new_off = get_new_entry(); if (lib_off == 0) lib_off = save_str(lib_name); sym_off = save_str(sym_name); /* LINTED */ new_bep = (binding_entry *)((char *)bhp + new_off); new_bep->be_sym_name = sym_off; new_bep->be_lib_name = lib_off; new_bep->be_count = 1; new_bep->be_next = cur_off; if (prev_off) { /* LINTED */ prev_bep = (binding_entry *)((char *)bhp + prev_off); prev_bep->be_next = new_off; } else /* * Insert at head of list. */ bhp->bh_bkts[bktno].bb_head = new_off; } } bt_unlock(&bhp->bh_bkts[bktno].bb_lock); (void) sigprocmask(SIG_SETMASK, &omask, NULL); return (symp->st_value); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _BINDINGS_H #define _BINDINGS_H #include #ifdef __cplusplus extern "C" { #endif #define BINDVERS 2 #define BINDCURVERS BINDVERS #define DEFFILE "/tmp/bindings.data" #define FILEENV "BT_BUFFER" #define BLKSIZE 0x4000 #define STRBLKSIZE 0x1000 #define DEFBKTS 3571 /* nice big prime number */ #define MASK (~(unsigned long)0<<28) typedef struct _bind_entry { unsigned int be_sym_name; unsigned int be_lib_name; unsigned int be_count; unsigned int be_next; } binding_entry; typedef struct { unsigned int bb_head; /* first entry in bucket */ unsigned int bb_pad; /* maintain alignment for 32/64bit */ lwp_mutex_t bb_lock; /* bucket chain lock */ } binding_bucket; typedef struct { unsigned int bh_vers; unsigned int bh_size; lwp_mutex_t bh_lock; unsigned int bh_end; unsigned int bh_bktcnt; unsigned int bh_strcur; /* current strbuff ptr */ unsigned int bh_strend; /* end of current strbuf */ lwp_mutex_t bh_strlock; /* mutex to protect strings */ binding_bucket bh_bkts[DEFBKTS]; } bindhead; #ifdef __cplusplus } #endif #endif /* _BINDINGS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include "bindings.h" void usage() { (void) printf("usage: dumpbind [-pqsc] \n"); (void) printf("\t-p\tdisplay output in parsable format\n"); (void) printf("\t-q\tquery all mutex_locks in data buffer\n"); (void) printf("\t-c\tclear all mutex_locks in data buffer\n"); (void) printf("\t-s\tset all mutex_locks in data buffer\n"); (void) printf("\t-b\tprint bucket usage statistics\n"); } /* * Returns 1 if lock held - 0 otherwise. */ static int query_lock(lwp_mutex_t *lock) { if (_lwp_mutex_trylock(lock) == 0) { (void) _lwp_mutex_unlock(lock); return (0); } else return (1); } static void query_buffer_locks(bindhead * bhp) { int i, bkt_locks_held = 0; (void) printf("bh_strlock: "); if (query_lock(&bhp->bh_strlock) == 1) (void) printf("lock held\n"); else (void) printf("free\n"); (void) printf("bh_lock: "); if (query_lock(&bhp->bh_lock) == 1) (void) printf("lock held\n"); else (void) printf("free\n"); (void) printf("Buckets: %d - locks held:\n", bhp->bh_bktcnt); for (i = 0; i < bhp->bh_bktcnt; i++) { if (query_lock(&bhp->bh_bkts[i].bb_lock) == 1) { bkt_locks_held++; (void) printf("\tbkt[%d]: lock held\n", i); } } if (bkt_locks_held == 0) (void) printf("\tnone.\n"); else (void) printf("\t[%d bucket(s) locked]\n", bkt_locks_held); } static void clear_buffer_locks(bindhead * bhp) { int i; if (query_lock(&bhp->bh_strlock) == 1) { (void) _lwp_mutex_unlock(&bhp->bh_strlock); (void) printf("bh_strlock: cleared\n"); } if (query_lock(&bhp->bh_lock) == 1) { (void) _lwp_mutex_unlock(&bhp->bh_lock); (void) printf("bh_lock: cleared\n"); } for (i = 0; i < bhp->bh_bktcnt; i++) { if (query_lock(&bhp->bh_bkts[i].bb_lock) == 1) { (void) _lwp_mutex_unlock(&bhp->bh_bkts[i].bb_lock); (void) printf("bkt[%d]: lock cleared\n", i); } } } static void set_buffer_locks(bindhead * bhp) { int i; for (i = 0; i < bhp->bh_bktcnt; i++) (void) _lwp_mutex_lock(&bhp->bh_bkts[i].bb_lock); (void) _lwp_mutex_lock(&bhp->bh_strlock); (void) _lwp_mutex_lock(&bhp->bh_lock); } int main(int argc, char **argv) { int fd; char *fname, *format_string; bindhead *bhp, *tmp_bhp; int i, c; int bflag = 0, pflag = 0, qflag = 0, cflag = 0, sflag = 0; ulong_t symcount, callcount; while ((c = getopt(argc, argv, "bspcq")) != EOF) switch (c) { case 'b': bflag++; break; case 'p': pflag++; break; case 'q': qflag++; break; case 'c': cflag++; break; case 's': sflag++; break; case '?': usage(); return (1); } if (optind == argc) { usage(); return (1); } fname = argv[optind]; if ((fd = open(fname, O_RDWR)) == -1) { (void) fprintf(stderr, "dumpbindings: unable to open file: %s\n", fname); perror("open"); return (1); } /* LINTED */ if ((bhp = (bindhead *)mmap(0, sizeof (bindhead), (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0)) == MAP_FAILED) { (void) fprintf(stderr, "dumpbind: mmap failed\n"); perror("mmap"); return (1); } if (qflag) { query_buffer_locks(bhp); return (0); } if (cflag) { clear_buffer_locks(bhp); return (0); } if (sflag) { set_buffer_locks(bhp); return (0); } /* LINTED */ if ((tmp_bhp = (bindhead *)mmap(0, bhp->bh_size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0)) == MAP_FAILED) { (void) fprintf(stderr, "dumpbind: remap: mmap failed\n"); perror("mmap"); return (1); } (void) close(fd); (void) munmap((void *)bhp, sizeof (bindhead)); bhp = tmp_bhp; if (pflag) format_string = "%s|%s|%8d\n"; else { if (!bflag) { (void) printf(" " "Bindings Summary Report\n\n" "Library Symbol" " Call Count\n" "----------------------------------------------" "--------------------------\n"); } format_string = "%-35s %-25s %5d\n"; } symcount = 0; callcount = 0; for (i = 0; i < bhp->bh_bktcnt; i++) { int ent_cnt = 0; binding_entry * bep; unsigned int bep_off = bhp->bh_bkts[i].bb_head; while (bep_off) { /* LINTED */ bep = (binding_entry *)((char *)bhp + bep_off); if (!bflag) { /* LINTED */ (void) printf(format_string, (char *)bhp + bep->be_lib_name, (char *)bhp + bep->be_sym_name, bep->be_count); symcount++; callcount += bep->be_count; } bep_off = bep->be_next; ent_cnt++; } if (bflag) (void) printf("bkt[%d] - %d entries\n", i, ent_cnt); } if (!bflag && !pflag) { (void) printf("----------------------------------------------" "--------------------------\n" "Symbol Count: %lu Call Count: %lu\n\n", symcount, callcount); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include static const char *token = ":"; void build_env_list(Elist **list, const char *env) { char *envstr; char *tok; char *lasts; if ((envstr = getenv(env)) == NULL) return; envstr = strdup(envstr); tok = strtok_r(envstr, token, &lasts); while (tok) { Elist *lp; if ((lp = (Elist *)malloc(sizeof (Elist))) == NULL) { (void) printf("build_list: malloc failed\n"); exit(1); } lp->l_libname = strdup(tok); lp->l_next = *list; *list = lp; tok = strtok_r(NULL, token, &lasts); } free(envstr); } Elist * check_list(Elist *list, const char *str) { const char *basestr; if (list == NULL) return (NULL); /* * Is this a basename or a relative path name */ if ((basestr = strrchr(str, '/')) != NULL) basestr++; else basestr = str; for (; list; list = list->l_next) { if (strchr(list->l_libname, '/') == NULL) { if (strcmp(basestr, list->l_libname) == 0) return (list); } else { if (strcmp(str, list->l_libname) == 0) return (list); } } return (NULL); } char * checkenv(const char *env) { char *envstr; if ((envstr = getenv(env)) == NULL) return (NULL); while (*envstr == ' ') envstr++; if (*envstr == '\0') return (NULL); return (envstr); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * All rights reserved. */ #ifndef _ENV_H #define _ENV_H typedef struct elist { char *l_libname; struct elist *l_next; } Elist; extern void build_env_list(Elist **, const char *); extern Elist *check_list(Elist *, const char *); extern char *checkenv(const char *); #endif /* _ENV_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include "hash.h" static int hash_string(const char *, long); hash * make_hash(size_t size) { hash *ptr; ptr = malloc(sizeof (*ptr)); ptr->size = size; ptr->table = malloc((size_t)(sizeof (hash_entry *) * size)); (void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size); ptr->start = NULL; ptr->hash_type = String_Key; return (ptr); } hash * make_ihash(size_t size) { hash *ptr; ptr = malloc(sizeof (*ptr)); ptr->size = size; ptr->table = malloc(sizeof (hash_entry *) * size); (void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size); ptr->start = NULL; ptr->hash_type = Integer_Key; return (ptr); } char ** get_hash(hash *tbl, char *key) { long bucket; hash_entry *tmp, *new; if (tbl->hash_type == String_Key) { tmp = tbl->table[bucket = hash_string(key, tbl->size)]; } else { tmp = tbl->table[bucket = labs((long)key) % tbl->size]; } if (tbl->hash_type == String_Key) { while (tmp != NULL) { if (strcmp(tmp->key, key) == 0) { return (&tmp->data); } tmp = tmp->next_entry; } } else { while (tmp != NULL) { if (tmp->key == key) { return (&tmp->data); } tmp = tmp->next_entry; } } /* * not found.... * insert new entry into bucket... */ new = malloc(sizeof (*new)); new->key = ((tbl->hash_type == String_Key)?strdup(key):key); /* * hook into chain from tbl... */ new->right_entry = NULL; new->left_entry = tbl->start; tbl->start = new; /* * hook into bucket chain */ new->next_entry = tbl->table[bucket]; tbl->table[bucket] = new; new->data = NULL; /* so we know that it is new */ return (&new->data); } char ** find_hash(hash *tbl, const char *key) { hash_entry *tmp; if (tbl->hash_type == String_Key) { tmp = tbl->table[hash_string(key, tbl->size)]; for (; tmp != NULL; tmp = tmp->next_entry) { if (strcmp(tmp->key, key) == 0) { return (&tmp->data); } } } else { tmp = tbl->table[labs((long)key) % tbl->size]; for (; tmp != NULL; tmp = tmp->next_entry) { if (tmp->key == key) { return (&tmp->data); } } } return (NULL); } char * del_hash(hash *tbl, const char *key) { ulong_t bucket; hash_entry * tmp, * prev = NULL; if (tbl->hash_type == String_Key) { bucket = hash_string(key, tbl->size); } else { bucket = labs((long)key) % tbl->size; } if ((tmp = tbl->table[bucket]) == NULL) { return (NULL); } else { if (tbl->hash_type == String_Key) { while (tmp != NULL) { if (strcmp(tmp->key, key) == 0) { break; /* found item to delete ! */ } prev = tmp; tmp = tmp->next_entry; } } else { while (tmp != NULL) { if (tmp->key == key) { break; } prev = tmp; tmp = tmp->next_entry; } } if (tmp == NULL) { return (NULL); /* not found */ } } /* * tmp now points to entry marked for deletion, prev to * item preceding in bucket chain or NULL if tmp is first. * remove from bucket chain first.... */ if (tbl->hash_type == String_Key) { free(tmp->key); } if (prev != NULL) { prev->next_entry = tmp->next_entry; } else { tbl->table[bucket] = tmp->next_entry; } /* * now remove from tbl chain.... */ if (tmp->right_entry != NULL) { /* not first in chain.... */ tmp->right_entry->left_entry = (tmp->left_entry ? tmp->left_entry->right_entry: NULL); } else { tbl->start = (tmp->left_entry ?tmp->left_entry->right_entry: NULL); } return (tmp->data); } size_t operate_hash(hash *tbl, void (*ptr)(), const char *usr_arg) { hash_entry *tmp = tbl->start; size_t c = 0; while (tmp) { (*ptr)(tmp->data, usr_arg, tmp->key); tmp = tmp->left_entry; c++; } return (c); } size_t operate_hash_addr(hash *tbl, void (*ptr)(), const char *usr_arg) { hash_entry *tmp = tbl->start; size_t c = 0; while (tmp) { (*ptr)(&(tmp->data), usr_arg, tmp->key); tmp = tmp->left_entry; c++; } return (c); } void destroy_hash(hash *tbl, int (*ptr)(), const char *usr_arg) { hash_entry * tmp = tbl->start, * prev; while (tmp) { if (ptr) { (void) (*ptr)(tmp->data, usr_arg, tmp->key); } if (tbl->hash_type == String_Key) { free(tmp->key); } prev = tmp; tmp = tmp->left_entry; free((char *)prev); } free((char *)tbl->table); free(tbl); } static int hash_string(const char *s, long modulo) { unsigned int result = 0; int i = 1; while (*s != '\0') { result += (*s++ << i++); } /* LINTED */ return ((int)(result % modulo)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _HASH_H #define _HASH_H typedef struct hash_entry { struct hash_entry *next_entry; struct hash_entry *right_entry; struct hash_entry *left_entry; char *key; char *data; } hash_entry; typedef struct hash { size_t size; hash_entry **table; hash_entry *start; enum hash_type { String_Key = 0, Integer_Key = 1 } hash_type; } hash; extern hash *make_hash(size_t); extern hash *make_ihash(size_t); extern char **get_hash(hash *, char *); extern char **find_hash(hash *, const char *); extern char *del_hash(hash *, const char *); extern size_t operate_hash(hash *, void (*)(), const char *); extern void destroy_hash(hash *, int (*)(), const char *); #endif /* _HASH_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _MACH_DOT_H #define _MACH_DOT_H #include #include #ifdef __cplusplus extern "C" { #endif #if defined(__sparc) #define GETARG0(regset) regset->lr_rego0 #define GETARG1(regset) regset->lr_rego1 #define GETARG2(regset) regset->lr_rego2 #define GETARG3(regset) regset->lr_rego3 #define GETARG4(regset) regset->lr_rego4 #define GETARG5(regset) regset->lr_rego5 #define GETFRAME(regset) regset->lr_rego6 #define GETPREVPC(regset) regset->lr_rego7 #elif defined(__i386) #define GETARG0(regset) (((ulong_t *)regset->lr_esp)[1]) #define GETARG1(regset) (((ulong_t *)regset->lr_esp)[2]) #define GETARG2(regset) (((ulong_t *)regset->lr_esp)[3]) #define GETARG3(regset) (((ulong_t *)regset->lr_esp)[4]) #define GETARG4(regset) (((ulong_t *)regset->lr_esp)[5]) #define GETARG5(regset) (((ulong_t *)regset->lr_esp)[6]) #define GETFRAME(regset) (regset->lr_ebp) #define GETPREVPC(regset) (*(uintptr_t *)regset->lr_esp) #elif defined(__amd64) #define GETARG0(regset) regset->lr_rdi #define GETARG1(regset) regset->lr_rsi #define GETARG2(regset) regset->lr_rdx #define GETARG3(regset) regset->lr_rcx #define GETARG4(regset) regset->lr_r8 #define GETARG5(regset) regset->lr_r9 #define GETFRAME(regset) (regset->lr_rbp) #define GETPREVPC(regset) (*(uintptr_t *)regset->lr_rsp) #else #error unsupported architecture! #endif #ifdef __cplusplus } #endif #endif /* _MACH_DOT_H */ # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: la_version; # Audit interfaces la_objopen; $if _sparc $if _ELF32 la_sparcv8_pltenter; $elif _ELF64 la_sparcv9_pltenter; $else $error unknown sparc ELFCLASS $endif $elif _x86 $if _ELF32 la_i86_pltenter; $elif _ELF64 la_amd64_pltenter; $else $error unknown x86 ELFCLASS $endif $else $error unknown platform $endif local: *; }; # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: la_version; # Audit interfaces la_objopen; $if _ELF32 la_pltexit; $elif _ELF64 la_pltexit64; $else $error unknown ELFCLASS $endif $if _sparc $if _ELF32 la_sparcv8_pltenter; $elif _ELF64 la_sparcv9_pltenter; $else $error unknown sparc ELFCLASS $endif $elif _x86 $if _ELF32 la_i86_pltenter; $elif _ELF64 la_amd64_pltenter; $else $error unknown x86 ELFCLASS $endif $else $error unknown platform $endif local: *; }; # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: la_version; # Audit interfaces la_objopen; la_preinit; $if _ELF32 la_symbind32; $elif _ELF64 la_symbind64; $else $error unknown ELFCLASS $endif local: *; }; # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: la_version; # Audit interfaces la_objopen; $if _ELF32 la_pltexit; la_symbind32; $elif _ELF64 la_pltexit64; la_symbind64; $else $error unknown ELFCLASS $endif $if _sparc $if _ELF32 la_sparcv8_pltenter; $elif _ELF64 la_sparcv9_pltenter; $else $error unknown sparc ELFCLASS $endif $elif _x86 $if _ELF32 la_i86_pltenter; $elif _ELF64 la_amd64_pltenter; $else $error unknown x86 ELFCLASS $endif $else $error unknown platform $endif local: *; }; # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: la_version; # Audit interfaces la_objopen; la_objclose; $if _sparc $if _ELF32 la_sparcv8_pltenter; $elif _ELF64 la_sparcv9_pltenter; $else $error unknown sparc ELFCLASS $endif $elif _x86 $if _ELF32 la_i86_pltenter; $elif _ELF64 la_amd64_pltenter; $else $error unknown x86 ELFCLASS $endif $else $error unknown platform $endif local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "env.h" #include "hash.h" typedef struct { float d_time; int d_count; const char *d_symname; } d_entry; typedef struct list { d_entry *l_dep; struct list *l_next; } List; static Elist *bindto_list = NULL; static Elist *bindfrom_list = NULL; static int initialized; extern long long gethrvtime(); static const char *progname; static long long starts[1000]; static long long accounted[1000]; /* time accounted for */ static int counter = 0; static float total_time = 0.0; static List *list_head = NULL; static hash *tbl; static sigset_t iset; static void list_insert(d_entry *dep) { List *new_list; List *cur; List *prev; if ((new_list = malloc(sizeof (List))) == NULL) { (void) printf("libperfcnt.so: malloc failed - " "can't print summary\n"); exit(1); } new_list->l_dep = dep; if (list_head == NULL) { list_head = new_list; new_list->l_next = NULL; return; } for (cur = list_head, prev = NULL; (cur && (cur->l_dep->d_time < dep->d_time)); prev = cur, cur = cur->l_next) ; /* * insert at head of list */ if (prev == NULL) { new_list->l_next = list_head; list_head = new_list; return; } prev->l_next = new_list; new_list->l_next = cur; } uint_t la_version(uint_t version) { int fd; char buffer[100]; if (version > LAV_CURRENT) (void) fprintf(stderr, "perfcnt.so.1: unexpected version: %d\n", version); (void) sprintf(buffer, "/proc/%d", (int)getpid()); if ((fd = open(buffer, O_RDWR)) >= 0) { long state = PR_MSACCT; if (ioctl(fd, PIOCSET, &state) == -1) perror("PIOCSET"); (void) close(fd); } initialized++; tbl = make_hash(213); build_env_list(&bindto_list, (const char *)"PERFCNT_BINDTO"); build_env_list(&bindto_list, (const char *)"PERFCNT_BINDFROM"); /* * Initalize iset to the full set of signals to be masked durring * pltenter/pltexit */ (void) sigfillset(&iset); return (LAV_CURRENT); } /* ARGSUSED1 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { static int first = 1; uint_t flags = 0; if (first) { progname = lmp->l_name; first = 0; } if (bindto_list == NULL) flags = LA_FLG_BINDTO; else { if (check_list(bindto_list, lmp->l_name)) flags = LA_FLG_BINDTO; } if (bindfrom_list == NULL) flags |= LA_FLG_BINDFROM; else { if (check_list(bindfrom_list, lmp->l_name)) flags |= LA_FLG_BINDFROM; } return (flags); } /* ARGSUSED1 */ #if defined(__sparcv9) uintptr_t la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__sparc) uintptr_t la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) #elif defined(__amd64) uintptr_t la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__i386) uintptr_t la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) #endif { accounted[counter] = 0; starts[counter] = gethrvtime(); counter++; return (symp->st_value); } /* ARGSUSED1 */ #if defined(_LP64) /* ARGSUSED */ uintptr_t la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, uintptr_t retval, const char *sym_name) #else uintptr_t la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, uintptr_t retval) #endif { d_entry **dep; long long time_used; sigset_t oset; #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif (void) sigprocmask(SIG_BLOCK, &iset, &oset); counter--; time_used = gethrvtime() - starts[counter]; dep = (d_entry **)get_hash(tbl, (char *)sym_name); if (*dep == NULL) { char *ptr = malloc(sizeof (d_entry)); /* LINTED */ (*dep) = (d_entry *)ptr; (*dep)->d_count = 0; (*dep)->d_time = 0.0; (*dep)->d_symname = sym_name; } if (counter) accounted[counter - 1] += time_used; ((*dep)->d_count)++; (*dep)->d_time += (double)((time_used - accounted[counter]) / 1.0e9); (void) sigprocmask(SIG_SETMASK, &oset, NULL); return (retval); } /* ARGSUSED1 */ static void scanlist(d_entry *dep, void *food, char *name) { total_time += dep->d_time; list_insert(dep); } #pragma fini(cleanup) static void cleanup() { List *cur; (void) operate_hash(tbl, scanlist, NULL); (void) printf("\n\nPerf Counts for: %s\n\n", progname); (void) printf("%20s\tc_count\t tim\t\tavg. tim\ttot. %%\n", "SYMBOL"); (void) printf("--------------------------------------------------" "-------------------\n"); for (cur = list_head; cur; cur = cur->l_next) { d_entry *dep = cur->l_dep; float tim = dep->d_time * 1000000; (void) printf("%20s\t%d\t%8.2f\t%8.2f\t%2.2f%%\n", dep->d_symname, dep->d_count, tim, tim / dep->d_count, ((dep->d_time / total_time) * 100.0)); } (void) printf("--------------------------------------------------" "-------------------\n"); (void) printf("\t\t\t\t\t\tTotal Time: %8.2f\n", total_time * 1000000); } #!/bin/ksh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. # usage() { echo "usage: perfcnt -[$optlet] utility [utility arguments]" echo " -f " echo " A colon seperated list of libraries that are to be" echo " traced. Only calls from these libraries will be" echo " traced. The default is to trace all calls." echo " -t " echo " A colon seperated list of libraries that are to be" echo " traced. Only calls to these libraries will be" echo " traced. The default is to trace all calls." echo " -l " echo " Specify an alternate perfcnt.so to use." } bindto="" bindfrom="" perfcntlib32="/opt/SUNWonld/lib/32/perfcnt.so.1" perfcntlib64="/opt/SUNWonld/lib/64/perfcnt.so.1" optlet="f:t:l:" if [[ $# -lt 1 ]]; then usage exit 1 fi while getopts $optlet c do case $c in f) bindfrom="$OPTARG" ;; t) bindto="$OPTARG" ;; l) perfcntlib32="$OPTARG" perfcntlib64="$OPTARG" ;; \?) usage exit 1 ;; esac done shift `expr $OPTIND - 1` # # Build environment variables # PERFCNT_BINDTO="$bindto" \ PERFCNT_BINDFROM="$bindfrom" \ LD_AUDIT_32="$perfcntlib32" \ LD_AUDIT_64="$perfcntlib64" \ $* exit 0 #!/bin/ksh -p # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. usage() { echo "usage: sotruss [-F:-T:-o:-f] utility [utility arguments]" echo " -F " echo " A colon seperated list of libraries that are to be" echo " traced. Only calls from these libraries will be" echo " traced. The default is to trace calls from the" echo " main executable." echo " -T " echo " A colon seperated list of libraries that are to be" echo " traced. Only calls to these libraries will be" echo " traced. The default is to trace all calls." echo " -o " echo " sotruss output will be directed to 'outputfile'." echo " by default it is placed on stdout." echo " -f" echo " Follow all children created by fork() and also" echo " print truss output for the children. This also" echo " causes a 'pid' to be added to each truss output line." } bindto="" bindfrom="" outfile="" noindentopt="" trusslib32="/usr/lib/link_audit/32/truss.so.1" trusslib64="/usr/lib/link_audit/64/truss.so.1" pidopt="" noexitopt="1" optlet="eF:T:o:fl:i" if [[ $# -lt 1 ]]; then usage exit 1 fi while getopts $optlet c do case $c in F) bindfrom="$OPTARG" ;; T) bindto="$OPTARG" ;; o) outfile="$OPTARG" ;; l) trusslib32="$OPTARG" trusslib64="$OPTARG" ;; f) pidopt="1" ;; i) noindentopt="1" ;; e) noexitopt="" ;; \?) usage exit 1 ;; esac done shift `expr $OPTIND - 1` # # Build environment variables # TRUSS_BINDTO="$bindto" \ TRUSS_BINDFROM="$bindfrom" \ TRUSS_OUTPUT="$outfile" \ TRUSS_PID="$pidopt" \ TRUSS_NOINDENT="$noindentopt" \ TRUSS_NOEXIT="$noexitopt" \ LD_AUDIT_32="$trusslib32" \ LD_AUDIT_64="$trusslib64" \ "$@" exit 0 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include "env.h" static Elist *bindto_list = NULL; static Elist *bindfrom_list = NULL; static FILE *output = stdout; uint_t la_version(uint_t version) { if (version < LAV_CURRENT) { (void) fprintf(stderr, "symbindrep.so: unexpected version: %d\n", version); return (0); } build_env_list(&bindto_list, (const char *)"SYMBINDREP_BINDTO"); build_env_list(&bindfrom_list, (const char *)"SYMBINDREP_BINDFROM"); #ifdef _LP64 (void) fprintf(output, " Symbol Bindings\n\n" "Referencing Defining\n" "Object Object Symbol\n" "---------------------------------------------------------------" "-------------------\n"); #else (void) fprintf(output, " Symbol Bindings\n\n" "Referencing Defining\n" "Object Object Symbol\n" "---------------------------------------------------------------" "---\n"); #endif return (LAV_CURRENT); } /* ARGSUSED1 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { uint_t flags; if ((bindto_list == NULL) || (check_list(bindto_list, lmp->l_name))) flags = LA_FLG_BINDTO; else flags = 0; if ((bindfrom_list == NULL) || (check_list(bindfrom_list, lmp->l_name))) flags |= LA_FLG_BINDFROM; *cookie = (uintptr_t)lmp->l_name; return (flags); } /* ARGSUSED1 */ #if defined(_LP64) uintptr_t la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook, uintptr_t *defcook, uint_t *sb_flags, const char *sym_name) #else uintptr_t la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook, uintptr_t *defcook, uint_t *sb_flags) #endif { #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif (void) fprintf(output, "%-28s %-28s %s\n", (char *)(*refcook), (char *)(*defcook), sym_name); return (symp->st_value); } /* * Since we only want to report on the symbol bindings for this * process and we *do not* want the actual program to run we exit * at this point. */ /* ARGSUSED0 */ void la_preinit(uintptr_t *cookie) { (void) fflush(output); exit(0); } #!/bin/ksh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. usage() { echo "usage: symbindrep -[$optlet] utility" echo " -f " echo " A colon sperated list of libraries that will have" echo " symbol references tracked. Only symbol references" echo " originating from these libraries will be tracked." echo " The default is to track symbol references from" echo " all libraries." echo " -t " echo " A colon separated list of libraries to track" echo " symbol bindings. Only bindings to objects in" echo " these objects will be tracked. The default is to" echo " track bindings to all objects." echo " -l " echo " specify an alternate symbindrep.so to use." } bindto="" bindfrom="" symbindreplib32="/opt/SUNWonld/lib/32/symbindrep.so.1" symbindreplib64="/opt/SUNWonld/lib/64/symbindrep.so.1" optlet="f:t:l:" while getopts $optlet c do case $c in f) bindfrom="$OPTARG" ;; t) bindto="$OPTARG" ;; l) symbindreplib32="$OPTARG" symbindreplib64="$OPTARG" ;; \?) usage exit 1 ;; esac done shift `expr $OPTIND - 1` # # Build environment variables # SYMBINDREP_BINDTO="$bindto" \ SYMBINDREP_BINDFROM="$bindfrom" \ LD_BIND_NOW=1 \ LD_AUDIT_32="$symbindreplib32" \ LD_AUDIT_64="$symbindreplib64" \ $* exit 0 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include "env.h" #include "mach.h" static Elist *bindto_list = NULL; static Elist *bindfrom_list = NULL; static uint_t pidout = 0; static pid_t pid; static FILE *outfile = stderr; static uint_t indent = 1; static uint_t indent_level = 1; static uint_t trussall = 0; static uint_t noexit = 0; static sigset_t iset; /* * It's not possible to gather the return code on routines * which actually have a dependence on the 'stack frame structure'. * Below is a list of known symbols which have this dependency, * truss.so will disable the la_pltexit() entry point for these * routines, which will remove the requirement for the extra * stackframe that the link_auditing interface creates. * * NOTE: this list *must* be mainted in alphabetical order. * if this list ever became to long a faster search mechanism * should be considered. */ static char *spec_sym[] = { #if defined(__sparc) ".stret1", ".stret2", ".stret4", ".stret8", #endif "__getcontext", "_getcontext", "_getsp", "_longjmp", "_setcontext", "_setjmp", "_siglongjmp", "_sigsetjmp", "_vfork", "getcontext", "getsp", "longjmp", "setcontext", "setjmp", "siglongjmp", "sigsetjmp", "vfork", (char *)0 }; uint_t la_version(uint_t version) { char *str; if (version > LAV_CURRENT) (void) fprintf(stderr, "truss.so: unexpected version: %d\n", version); build_env_list(&bindto_list, (const char *)"TRUSS_BINDTO"); build_env_list(&bindfrom_list, (const char *)"TRUSS_BINDFROM"); if (checkenv((const char *)"TRUSS_PID")) { pidout = 1; pid = getpid(); } else { char *str = "LD_AUDIT="; /* * This disables truss output in subsequent fork()/exec * processes. */ (void) putenv(str); } if (checkenv((const char *)"TRUSS_NOEXIT")) { noexit++; indent = 0; } if (checkenv((const char *)"TRUSS_NOINDENT")) indent = 0; if (checkenv((const char *)"TRUSS_ALL")) trussall++; str = checkenv((const char *)"TRUSS_OUTPUT"); if (str != NULL) { FILE *fp; char fname[MAXPATHLEN]; if (pidout) (void) snprintf(fname, MAXPATHLEN, "%s.%d", str, (int)pid); else (void) strncpy(fname, str, MAXPATHLEN); fp = fopen(fname, (const char *)"w"); if (fp != NULL) { outfile = fp; } else { (void) fprintf(stderr, "truss.so: unable to open file=`%s': %s\n", fname, strerror(errno)); } } /* * Initalize iset to the full set of signals to be masked durring * pltenter/pltexit */ (void) sigfillset(&iset); return (LAV_CURRENT); } /* ARGSUSED1 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { uint_t flags; char *basename; static int first = 1; if ((bindto_list == NULL) || (trussall)) flags = LA_FLG_BINDTO; else if (check_list(bindto_list, lmp->l_name)) flags = LA_FLG_BINDTO; else flags = 0; if (((bindfrom_list == NULL) && first) || trussall || (check_list(bindfrom_list, lmp->l_name))) flags |= LA_FLG_BINDFROM; first = 0; if (flags) { if ((basename = strrchr(lmp->l_name, '/')) != NULL) basename++; else basename = lmp->l_name; *cookie = (uintptr_t)basename; } return (flags); } /* ARGSUSED1 */ #if defined(_LP64) uintptr_t la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook, uintptr_t *defcook, uint_t *sb_flags, const char *sym_name) #else uintptr_t la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook, uintptr_t *defcook, uint_t *sb_flags) #endif { #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif if (noexit) *sb_flags |= LA_SYMB_NOPLTEXIT; /* * Check to see if this symbol is one of the 'special' symbols. * If so we disable PLTEXIT calls for that symbol. */ if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0) { uint_t ndx; char *str; for (ndx = 0; (str = spec_sym[ndx]) != NULL; ndx++) { int cmpval; cmpval = strcmp(sym_name, str); if (cmpval < 0) break; if (cmpval == 0) { *sb_flags |= LA_SYMB_NOPLTEXIT; break; } } } return (symp->st_value); } /* ARGSUSED1 */ #if defined(__sparcv9) uintptr_t la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__sparc) uintptr_t la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) #elif defined(__amd64) uintptr_t la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__i386) uintptr_t la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags) #endif { char *istr; char *defname = (char *)(*defcookie); char *refname = (char *)(*refcookie); #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif sigset_t oset; (void) sigprocmask(SIG_BLOCK, &iset, &oset); if (pidout) (void) fprintf(outfile, "%5d:", (int)getpid()); if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0) istr = ""; else istr = "*"; (void) fprintf(outfile, "%-15s -> %15s:%-*s%s(0x%lx, 0x%lx, 0x%lx)\n", refname, defname, indent_level, istr, sym_name, (long)GETARG0(regset), (long)GETARG1(regset), (long)GETARG2(regset)); (void) fflush(outfile); if (indent && ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0)) indent_level++; (void) sigprocmask(SIG_SETMASK, &oset, NULL); return (symp->st_value); } /* ARGSUSED1 */ #if defined(_LP64) /* ARGSUSED */ uintptr_t la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, uintptr_t retval, const char *sym_name) #else uintptr_t la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, uintptr_t retval) #endif { char *defname = (char *)(*defcookie); char *refname = (char *)(*refcookie); sigset_t oset; #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif (void) sigprocmask(SIG_BLOCK, &iset, &oset); if (pidout) (void) fprintf(outfile, "%5d:", (int)pid); if (indent) indent_level--; (void) fprintf(outfile, "%-15s -> %15s:%*s%s - 0x%lx\n", refname, defname, indent_level, "", sym_name, (ulong_t)retval); (void) fflush(outfile); (void) sigprocmask(SIG_SETMASK, &oset, NULL); return (retval); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include "env.h" #include "mach.h" #include "who.h" static int detail_syms = 0; /* display detail symbol information */ static Objinfo *objhead = NULL; /* head of object list */ static Elist *funclist = NULL; static sigset_t iset; static void add_object(Objinfo **objlist, Link_map *lmp) { Objinfo *op, *cur, *prev; Elf_Ehdr *ehdr; Elf_Phdr *phdr; caddr_t lpc, hpc; int i; if ((op = calloc(1, sizeof (Objinfo))) == NULL) { (void) fprintf(stderr, "who.so.1: calloc failed\n"); exit(1); } lpc = hpc = (caddr_t)lmp->l_addr; /* LINTED */ ehdr = (Elf_Ehdr *)lpc; /* LINTED */ for (i = 0, phdr = (Elf_Phdr *)(ehdr->e_phoff + lpc); i < ehdr->e_phnum; i++, phdr++) { caddr_t _hpc; if ((phdr->p_type == PT_LOAD) && ((_hpc = phdr->p_vaddr + phdr->p_memsz + lpc) > hpc)) hpc = _hpc; } op->o_lpc = lpc; op->o_hpc = hpc; op->o_lmp = lmp; if (ehdr->e_type == ET_EXEC) op->o_flags |= FLG_OB_FIXED; if (*objlist == NULL) { *objlist = op; return; } /* * Do an insertion sort to maintain the list * in order. */ if ((*objlist)->o_lmp->l_addr > lmp->l_addr) { op->o_next = *objlist; *objlist = op; return; } for (prev = NULL, cur = *objlist; cur; prev = cur, cur = cur->o_next) { if (lpc < cur->o_lpc) break; } if (prev == NULL) { op->o_next = *objlist; *objlist = op; return; } prev->o_next = op; op->o_next = cur; } static void remove_object(Objinfo **objlist, Link_map *lmp) { Objinfo *cur, *prev; for (prev = NULL, cur = *objlist; cur; prev = cur, cur = cur->o_next) { if (cur->o_lmp == lmp) break; } /* * Did we find it? */ if (!cur) return; if (!prev) *objlist = cur->o_next; else prev->o_next = cur->o_next; if (cur->o_elf) { (void) elf_end(cur->o_elf); (void) close(cur->o_fd); } free(cur); } static void print_simple_address(void *pc) { Dl_info info; if (dladdr(pc, &info) == 0) { (void) fprintf(stderr, "\t: 0x%lx\n", (unsigned long)pc); return; } (void) fprintf(stderr, "\t%s:%s+0x%lx\n", info.dli_fname, info.dli_sname, (ulong_t)((uintptr_t)pc - (uintptr_t)info.dli_saddr)); } static void load_syms(Objinfo *op) { int fd; Elf *elf; Elf_Scn *scn; if (elf_version(EV_CURRENT) == EV_NONE) { op->o_flags |= FLG_OB_NOSYMS; return; } if ((fd = open(op->o_lmp->l_name, O_RDONLY)) == -1) { op->o_flags |= FLG_OB_NOSYMS; return; } if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { op->o_flags |= FLG_OB_NOSYMS; (void) close(fd); return; } scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { Elf_Shdr *shdr; Elf_Data *data; shdr = elf_getshdr(scn); if (shdr->sh_type != SHT_SYMTAB) continue; data = elf_getdata(scn, 0); op->o_syms = (Elf_Sym *)data->d_buf; /* LINTED */ op->o_symcnt = (uint_t)(shdr->sh_size / shdr->sh_entsize); scn = elf_getscn(elf, shdr->sh_link); data = elf_getdata(scn, 0); op->o_strs = (const char *)data->d_buf; } if (!op->o_syms) { (void) elf_end(elf); (void) close(fd); op->o_flags |= FLG_OB_NOSYMS; } } static void print_address(caddr_t pc) { Elf_Sym *sym, *_sym; Objinfo *op; int i; if (!detail_syms) { print_simple_address(pc); return; } for (op = objhead; op; op = op->o_next) { if ((pc >= op->o_lpc) && (pc <= op->o_hpc)) break; } if (op && (op->o_syms == NULL)) load_syms(op); if (!op || (op->o_flags & FLG_OB_NOSYMS)) { print_simple_address(pc); return; } sym = op->o_syms; if ((op->o_flags & FLG_OB_FIXED) == 0) pc = (caddr_t)((uintptr_t)pc - (uintptr_t)op->o_lpc); for (i = 0, _sym = op->o_syms; i < op->o_symcnt; i++, _sym++) { if (((uintptr_t)_sym->st_value < (uintptr_t)pc) && (_sym->st_value > sym->st_value)) sym = _sym; } (void) fprintf(stderr, "\t%s:%s+0x%lx\n", op->o_lmp->l_name, sym->st_name + op->o_strs, (ulong_t)((uintptr_t)pc - (uintptr_t)sym->st_value)); } static void print_stack(struct frame *sp) { FLUSHWIN(); while (sp && sp->fr_savpc) { print_address((caddr_t)sp->fr_savpc); sp = (struct frame *)((ulong_t)sp->fr_savfp + STACK_BIAS); } } uint_t la_version(uint_t version) { if (version > LAV_CURRENT) (void) fprintf(stderr, "who.so: unexpected version: %d\n", version); if (checkenv((const char *)"WHO_DETAIL")) detail_syms++; build_env_list(&funclist, (const char *)"WHOCALLS"); /* * Initalize iset to the full set of signals to be masked durring * pltenter/pltexit */ (void) sigfillset(&iset); return (LAV_CURRENT); } /* ARGSUSED1 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { add_object(&objhead, lmp); return (LA_FLG_BINDTO | LA_FLG_BINDFROM); } uint_t la_objclose(uintptr_t *cookie) { remove_object(&objhead, (Link_map *)(*cookie)); return (1); } /* ARGSUSED1 */ #if defined(__sparcv9) uintptr_t la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__sparc) uintptr_t la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) #elif defined(__amd64) uintptr_t la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, const char *sym_name) #elif defined(__i386) uintptr_t la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) #endif { sigset_t oset; #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif (void) sigprocmask(SIG_BLOCK, &iset, &oset); if (check_list(funclist, sym_name)) { struct frame *frame_p; (void) fprintf(stderr, "%s(0x%lx, 0x%lx, 0x%lx)\n", sym_name, (long)GETARG0(regset), (long)GETARG1(regset), (long)GETARG2(regset)); print_address((caddr_t)GETPREVPC(regset)); frame_p = (struct frame *)((ulong_t)GETFRAME(regset) + STACK_BIAS); print_stack(frame_p); (void) fflush(stdout); } (void) sigprocmask(SIG_SETMASK, &oset, NULL); return (symp->st_value); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef WHO_DOT_H #define WHO_DOT_H #include #include #include #include #if defined(__sparcv9) #define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr #define Elf_Shdr Elf64_Shdr #define Elf_Sym Elf64_Sym #define elf_getshdr elf64_getshdr #else #define Elf_Ehdr Elf32_Ehdr #define Elf_Phdr Elf32_Phdr #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define elf_getshdr elf32_getshdr #endif typedef struct objinfo { caddr_t o_lpc; /* low PC */ caddr_t o_hpc; /* high PC */ int o_fd; /* file descriptor */ Elf *o_elf; /* Elf pointer */ Elf_Sym *o_syms; /* symbol table */ uint_t o_symcnt; /* # of symbols */ const char *o_strs; /* symbol string table */ Link_map *o_lmp; uint_t o_flags; struct objinfo *o_next; } Objinfo; #define FLG_OB_NOSYMS 0x0001 /* no symbols available for obj */ #define FLG_OB_FIXED 0x0002 /* fixed address object */ #if defined(__sparc) #if defined(__GNUC__) #define FLUSHWIN() __asm__("ta 3"); #else /* !__GNUC__ */ #define FLUSHWIN() asm("ta 3"); #endif #endif #if defined(__x86) #define FLUSHWIN() #endif #ifndef STACK_BIAS #define STACK_BIAS 0 #endif #endif /* WHO_DOT_H */ #!/bin/ksh -p # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. usage() { cat 1>&2 << 'EOF' usage: whocalls [sl:] [utility arguments] whocalls will audit all function bindings between and any library it utilizes. Each time the function is called, a stack backtrace is displayed -l specify an alternate who.so to use. -s When available, examine and use the .symtab symbol table for local symbols (more expensive). EOF } optlet="sl:" if [[ $# -lt 2 ]]; then usage exit 1 fi wholib32="/usr/lib/link_audit/32/who.so.1" wholib64="/usr/lib/link_audit/64/who.so.1" detail="" while getopts $optlet c do case $c in l) wholib32="$OPTARG" wholib64="$OPTARG" ;; s) detail="1" ;; \?) usage exit 1 ;; esac done shift `expr $OPTIND - 1` func=$1 shift 1 LD_AUDIT_32="$wholib32" \ LD_AUDIT_64="$wholib64" \ WHO_DETAIL="$detail" \ WHOCALLS="$func" \ "$@" exit 0 .\" Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. .\" .\" CDDL HEADER START .\" .\" The contents of this file are subject to the terms of the .\" Common Development and Distribution License (the "License"). .\" You may not use this file except in compliance with the License. .\" .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE .\" or http://www.opensolaris.org/os/licensing. .\" See the License for the specific language governing permissions .\" and limitations under the License. .\" .\" When distributing Covered Code, include this CDDL HEADER in each .\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. .\" If applicable, add the following below this CDDL HEADER, with the .\" fields enclosed by brackets "[]" replaced with your own identifying .\" information: Portions Copyright [yyyy] [name of copyright owner] .\" .\" CDDL HEADER END .\" .if n .tr \-- .TH dumpbind 1 "18 Nov 1996" .SH NAME dumpbind \- dump the bindings found in a bindings.so.1 output file .SH SYNOPSIS .B dumpbind [ .B -pqsc ] .I bindings_file .SH AVAILABILITY .LP SUNWosdem .SH DESCRIPTION .B dumpbind parses the output file created by the .B bindings.so.1 .I Link-Auditing library and displays a summary of all of the bindings that are are recorded in it. .LP .B bindings.so.1 is a .I Link-Auditing library which monitors the bindings of function calls and stores the data in a common buffer pointed to by BT_OUTPUT. Because this library tracks procedure calls via the .I la_pltenter() .I Link-Auditing interface this library will record which functions are called as part of the execution of a program. This differs from the .B symbindrep example which performs a static analysis of all of the bindings that are recorded in a program without actually executing it. Also note that it is safe to use the same BT_BUFFER for multiple processes running concurrently. This means that a whole suite of applications can be run and the interfaces that are used as part of that suite are recorded. .LP The .B bindings.so.1 library is enabled by the setting of the following environment variables. .LP .TP 10 .B LD_AUDIT set this to the value of the bindings.so.1 .I Link-Auditing library. By setting this environment variable the gathering of bindings data is enabled. .TP .B BT_OUTPUT set this to the name of the common output buffer which will be maintained during the data gathering period. If this is not set the output buffer will default to .I /tmp/bindings.data. .TP .B BT_BINDFROM a colon separated list of libraries that are to be traced. Only calls from these libraries will be traced. The default is to trace all calls. .TP .B BT_BINDTO a colon separated list of libraries that are to be traced. Only calls to these libraries will be traced. The default is to trace all calls. .SH OPTIONS .TP 10 .B \-p display output in parseable format. .TP .B \-q query mutex_locks in bindings buffer and display there current status. This is when querying a problem with the bindings buffer. .TP .B \-c clear all mutex_locks currently held in the bindings buffer. .TP .B \-s set master mutex_lock in bindings buffer. This will cause any processes currently using this bindings buffer to hang until the lock is freed. .TP .B \-b print hash bucket usage statistics for the bindings buffer. .SH EXAMPLES Here is a sample of gathering data using the .B bindings.so.1 .I Link-Auditing library and then the examination of that data with the .B dumpbind command. .LP .nf .ft 3 polyslo 131% export BT_OUTPUT=/tmp/bindings.data polyslo 3563% LD_AUDIT=/opt/SUNWonld/lib/bindings.so.1 polyslo 3564% export LD_AUDIT polyslo 3565% ls /usr/ccs/bin admin gprof.flat.blurb nrform strip.orig ar help prof symorder ar.orig ld prs tsort as ld.orig prt unget cdc lex ranlib unifdef comb lorder regcmp val delta m4 rmdel vc dis make sact what dump mcs sccs yacc error mcs.orig sccsdiff yaccpar get nceucform size gprof ncform stanswer gprof.callg.blurb nm strip polyslo 3566% nm /usr/lib/libdl.so.1 /usr/lib/libdl.so.1: [Index] Value Size Type Bind Other Shndx Name ... [27] | 1788| 8|FUNC |GLOB |0 |7 |_dladdr [32] | 1772| 8|FUNC |GLOB |0 |7 |_dlclose [44] | 1796| 8|FUNC |GLOB |0 |7 |_dldump [29] | 1780| 8|FUNC |GLOB |0 |7 |_dlerror [26] | 1732| 8|FUNC |GLOB |0 |7 |_dlinfo [17] | 1740| 8|FUNC |LOCL |0 |7 |_dlmap [24] | 1748| 8|FUNC |GLOB |0 |7 |_dlmopen [23] | 1756| 8|FUNC |GLOB |0 |7 |_dlopen [48] | 1764| 8|FUNC |GLOB |0 |7 |_dlsym [38] | 0| 0|OBJT |GLOB |0 |ABS |_edata [21] | 1824| 0|OBJT |GLOB |0 |8 |_end [42] | 1820| 0|OBJT |GLOB |0 |8 |_etext [30] | 1804| 8|FUNC |GLOB |0 |7 |_ld_concurrency [34] | 1812| 8|FUNC |GLOB |0 |7 |bind_guard [47] | 1820| 4|OBJT |GLOB |0 |8 |dbg_mask [20] | 0| 0|FILE |LOCL |0 |ABS |dl.c [43] | 1788| 8|FUNC |WEAK |0 |7 |dladdr [22] | 1772| 8|FUNC |WEAK |0 |7 |dlclose [31] | 1796| 8|FUNC |WEAK |0 |7 |dldump [45] | 1780| 8|FUNC |WEAK |0 |7 |dlerror ... polyslo 136% unset LD_AUDIT .ft .fi .LP Unsetting LD_AUDIT has turned off the bindings data gathering and the output can now safely be examined by dumpbind. .LP .nf .ft3 polyslo 3567% unset LD_AUDIT polyslo 3568% dumpbind /tmp/bindings.data Bindings Summary Report Library Symbol Call Count ------------------------------------------------------------------------ /usr/lib/libc.so.1 textdomain 2 /usr/lib/libelf.so.1 elf_kind 1 /usr/lib/libc.so.1 munmap 1 /usr/lib/libc.so.1 strlen 353 /usr/lib/libc.so.1 .urem 3 /usr/lib/libc.so.1 iswprint 444 /usr/lib/libc.so.1 .udiv 11 /usr/lib/libc.so.1 time 1 /usr/lib/libc.so.1 .mul 361 /usr/lib/libc.so.1 closedir 1 /usr/lib/libc.so.1 _rw_read_held 36 /usr/lib/libelf.so.1 elf_strptr 34 /usr/lib/libc.so.1 lstat64 1 /usr/lib/libc.so.1 _realbufend 1203 /usr/lib/libc.so.1 qsort 3 /usr/lib/libc.so.1 _write 64 /usr/lib/libelf.so.1 _elf32_fsize 7 /usr/lib/libc.so.1 close 1 /usr/lib/libelf.so.1 elf_begin 1 /usr/lib/libelf.so.1 elf_version 1 /usr/lib/libc.so.1 _isatty 2 /usr/lib/libc.so.1 mmap 1 /usr/lib/libelf.so.1 elf_end 1 /usr/lib/libc.so.1 printf 628 /usr/lib/libc.so.1 calloc 2 ... /usr/lib/libc.so.1 __flsbuf 511 /usr/lib/libc.so.1 _close 1 /usr/lib/libc.so.1 _doprnt 630 /usr/lib/libc.so.1 ___errno 3 /usr/lib/libc.so.1 .umul 23 /usr/lib/libc.so.1 _thr_main 7 /usr/lib/libc.so.1 open 1 /usr/lib/libc.so.1 _sbrk_unlocked 8 /usr/lib/libc.so.1 mutex_lock 1 /usr/lib/libc.so.1 _setbufend 2 /usr/lib/libc.so.1 sprintf 2 /usr/lib/libc.so.1 setlocale 2 /usr/lib/libelf.so.1 elf_nextscn 15 /usr/lib/ld.so.1 dlsym 2 /usr/lib/libelf.so.1 _elf_getscn 34 /usr/lib/libc.so.1 _sbrk 8 /usr/lib/libc.so.1 _open64 1 /usr/lib/libc.so.1 _mutex_lock 88 /usr/lib/libc.so.1 exit 2 /usr/lib/libc.so.1 ioctl 1 /usr/lib/libc.so.1 getenv 17 /usr/lib/libc.so.1 _mutex_held 36 ------------------------------------------------------------------------ Symbol Count: 87 Call Count: 8272 polyslo 3570% .ft .fi .SH SEE ALSO .BR ld.so.1 (1) .br .TZ LLM .\" Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. .\" .\" CDDL HEADER START .\" .\" The contents of this file are subject to the terms of the .\" Common Development and Distribution License (the "License"). .\" You may not use this file except in compliance with the License. .\" .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE .\" or http://www.opensolaris.org/os/licensing. .\" See the License for the specific language governing permissions .\" and limitations under the License. .\" .\" When distributing Covered Code, include this CDDL HEADER in each .\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. .\" If applicable, add the following below this CDDL HEADER, with the .\" fields enclosed by brackets "[]" replaced with your own identifying .\" information: Portions Copyright [yyyy] [name of copyright owner] .\" .\" CDDL HEADER END .\" .if n .tr \-- .TH perfcnt 1 "18 Nov 1996" .SH NAME perfcnt \- trace the amount of time spent in each function call .SH SYNOPSIS .B perfcnt [ .B -f .I bindfromlist ] [ .B t .I bindtolist ] [ .B -l .I perfcntlib ] executable [executable arguments ...] .SH AVAILABILITY .LP SUNWosdem .SH DESCRIPTION .B perfcnt executes the specified command and tracks the amount of time that is spent in each procedure call. .B perfcnt traces all of the procedure calls that occur between dynamic objects via the .I Procedure Linkage Table, so only those procedure calls which are bound to the .I Procedure Linkage Table will be traced. .LP .B perfcnt has the limitation that it does not work with a threaded program nor any programs which use procedures which are dependent upon the stack frame. See .I NOTES below .SH OPTIONS .TP 10 .BI \-f " bindfromlist" A colon separated list of libraries that are to be traced. Only calls from these libraries will be traced. The default is to trace all calls. .TP .BI \-t " bindtolist" A colon separated list of libraries taht are to be traced. Only calls to these libraries will be traced. The default is to trace all calls. .TP .BI \-l " perfcntlib" specify an alternate perfcnt.so .I Link-Auditing library to use. .SH EXAMPLES The example tracks the usage of the libelf.so.1 library when performing a nm. .LP .nf .ft 3 % perfcnt -t/usr/lib/libelf.so.1 nm /usr/lib/libc.so.1 /usr/lib/libc.so.1: [Index] Value Size Type Bind Other Shndx Name [457] | 0| 0|NOTY |LOCL |0 |UNDEF | [2] | 148| 0|SECT |LOCL |0 |1 | [3] | 15232| 0|SECT |LOCL |0 |2 | [4] | 45120| 0|SECT |LOCL |0 |3 | [5] | 64024| 0|SECT |LOCL |0 |4 | \.\.\. [1893] | 347660| 88|FUNC |LOCL |0 |12 |ypstub_perror [1895] | 347280| 380|FUNC |LOCL |0 |12 |ypstub_sperror [714] | 663472| 8|OBJT |LOCL |0 |22 |zero Perf Counts for: nm SYMBOL c_count tim avg. tim tot. % --------------------------------------------------------------------- elf_getscn 1 4.03 4.03 0.01% elf_kind 1 4.36 4.36 0.01% _elf32_fsize 7 50.80 7.26 0.09% _elf32_xlatetom 6 67.47 11.24 0.11% elf_version 1 72.50 72.50 0.12% elf32_getshdr 33 77.42 2.35 0.13% elf_nextscn 33 83.36 2.53 0.14% elf_end 1 131.91 131.91 0.22% elf_getdata 2 138.74 69.37 0.23% elf_begin 1 171.74 171.74 0.29% elf32_getehdr 1 214.81 214.81 0.36% _elf_getscn 4254 9755.89 2.29 16.38% elf_strptr 4254 48784.97 11.47 81.91% --------------------------------------------------------------------- Total Time: 59557.98 .ft .fi .SH NOTES The .B perfcnt command is a demonstration of the .I Link-Auditing interface of the run-time linker (which is documented in .TZ LLM \), and it is not useful in all environments. This program will not work with a threaded application and should not be used with one. Also, in order to track the time spent in a procedure both the entry and exit of the procedure must be tracked. Because this causes an additional stack frame to be created for each procedure call it is not compatible with all library routines. More details on this can be found in the .I Link-Auditing section of .TZ LLM .SH SEE ALSO .BR ld.so.1 (1) .br .TZ LLM .\" Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. .\" .\" CDDL HEADER START .\" .\" The contents of this file are subject to the terms of the .\" Common Development and Distribution License (the "License"). .\" You may not use this file except in compliance with the License. .\" .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE .\" or http://www.opensolaris.org/os/licensing. .\" See the License for the specific language governing permissions .\" and limitations under the License. .\" .\" When distributing Covered Code, include this CDDL HEADER in each .\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. .\" If applicable, add the following below this CDDL HEADER, with the .\" fields enclosed by brackets "[]" replaced with your own identifying .\" information: Portions Copyright [yyyy] [name of copyright owner] .\" .\" CDDL HEADER END .\" .if n .tr \-- .TH symbindrep 1 "18 Nov 1996" .SH NAME symbindrep \- report on all symbol bindings required to load this object .SH SYNOPSIS .B symbindrep [ .B -f .I bindfromlist ] [ .B -t .I bindtolist ] [ .B -l .I symbindreplib ] .I funcname executable .SH AVAILABILITY .LP SUNWosdem .SH DESCRIPTION .B symbindrep is a simple example of a .I Link-Auditing library which reports on the symbol bindings performed by the run-time linker (ld.so.1) when loading an object. .B symbindrep will display all of the symbol bindings that occur between the executable and all of it's dependencies. After all symbol bindings have been performed .B symbindrep will terminate. No code from the executable is ever executed. .SH OPTIONS .TP 10 .BI \-f " bindfromlist" A colon separated list of libraries that are to be traced. Only symbol bindings from these libraries will be traced. The default is to report on all symbol bindings. .BI \-t " bindtolib" A colon separated list of libraries that are to be traced. Only symbol bindings to these libraries will be reported. The default is to trace all libraries. .BI \-l " symbindrep" specify an alternate symbindrep.so .I Link-Auditing library to use. .SH EXAMPLES This example reports on only the symbol bindings between nm and libelf.so.1. .LP .nf .ft 3 % symbindrep -t /usr/lib/libelf.so.1 -f nm nm Symbol Bindings Referencing Defining Object Object Symbol ------------------------------------------------------------------ nm /usr/lib/libelf.so.1 elf_version nm /usr/lib/libelf.so.1 elf_begin nm /usr/lib/libelf.so.1 elf_errmsg nm /usr/lib/libelf.so.1 elf_kind nm /usr/lib/libelf.so.1 elf_end nm /usr/lib/libelf.so.1 elf32_getehdr nm /usr/lib/libelf.so.1 elf_getscn nm /usr/lib/libelf.so.1 elf32_getshdr nm /usr/lib/libelf.so.1 elf_getdata nm /usr/lib/libelf.so.1 elf_nextscn nm /usr/lib/libelf.so.1 elf_getarhdr nm /usr/lib/libelf.so.1 elf_next nm /usr/lib/libelf.so.1 elf_strptr .ft .fi .SH SEE ALSO .BR ld.so.1 (1) .br .TZ LLM