17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*20c1c355SRod Evans  * Common Development and Distribution License (the "License").
6*20c1c355SRod Evans  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*20c1c355SRod Evans 
227c478bd9Sstevel@tonic-gate /*
23*20c1c355SRod Evans  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate #include	<stdlib.h>
267c478bd9Sstevel@tonic-gate #include	<unistd.h>
277c478bd9Sstevel@tonic-gate #include	<sys/types.h>
287c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
297c478bd9Sstevel@tonic-gate #include	<sys/lwp.h>
307c478bd9Sstevel@tonic-gate #include	<fcntl.h>
317c478bd9Sstevel@tonic-gate #include	<stdio.h>
327c478bd9Sstevel@tonic-gate #include	<sys/mman.h>
337c478bd9Sstevel@tonic-gate #include	<synch.h>
347c478bd9Sstevel@tonic-gate #include	<errno.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include	"bindings.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate void
usage()397c478bd9Sstevel@tonic-gate usage()
407c478bd9Sstevel@tonic-gate {
417c478bd9Sstevel@tonic-gate 	(void) printf("usage: dumpbind [-pqsc] <bindings.data>\n");
427c478bd9Sstevel@tonic-gate 	(void) printf("\t-p\tdisplay output in parsable format\n");
437c478bd9Sstevel@tonic-gate 	(void) printf("\t-q\tquery all mutex_locks in data buffer\n");
447c478bd9Sstevel@tonic-gate 	(void) printf("\t-c\tclear all mutex_locks in data buffer\n");
457c478bd9Sstevel@tonic-gate 	(void) printf("\t-s\tset all mutex_locks in data buffer\n");
467c478bd9Sstevel@tonic-gate 	(void) printf("\t-b\tprint bucket usage statistics\n");
477c478bd9Sstevel@tonic-gate }
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Returns 1 if lock held - 0 otherwise.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate static int
query_lock(lwp_mutex_t * lock)537c478bd9Sstevel@tonic-gate query_lock(lwp_mutex_t *lock) {
547c478bd9Sstevel@tonic-gate 	if (_lwp_mutex_trylock(lock) == 0) {
557c478bd9Sstevel@tonic-gate 		(void) _lwp_mutex_unlock(lock);
567c478bd9Sstevel@tonic-gate 		return (0);
577c478bd9Sstevel@tonic-gate 	} else
587c478bd9Sstevel@tonic-gate 		return (1);
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static void
query_buffer_locks(bindhead * bhp)627c478bd9Sstevel@tonic-gate query_buffer_locks(bindhead * bhp)
637c478bd9Sstevel@tonic-gate {
647c478bd9Sstevel@tonic-gate 	int	i, bkt_locks_held = 0;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	(void) printf("bh_strlock: ");
677c478bd9Sstevel@tonic-gate 	if (query_lock(&bhp->bh_strlock) == 1)
687c478bd9Sstevel@tonic-gate 		(void) printf("lock held\n");
697c478bd9Sstevel@tonic-gate 	else
707c478bd9Sstevel@tonic-gate 		(void) printf("free\n");
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	(void) printf("bh_lock: ");
737c478bd9Sstevel@tonic-gate 	if (query_lock(&bhp->bh_lock) == 1)
747c478bd9Sstevel@tonic-gate 		(void) printf("lock held\n");
757c478bd9Sstevel@tonic-gate 	else
767c478bd9Sstevel@tonic-gate 		(void) printf("free\n");
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	(void) printf("Buckets: %d - locks held:\n", bhp->bh_bktcnt);
797c478bd9Sstevel@tonic-gate 	for (i = 0; i < bhp->bh_bktcnt; i++) {
807c478bd9Sstevel@tonic-gate 		if (query_lock(&bhp->bh_bkts[i].bb_lock) == 1) {
817c478bd9Sstevel@tonic-gate 			bkt_locks_held++;
827c478bd9Sstevel@tonic-gate 			(void) printf("\tbkt[%d]: lock held\n", i);
837c478bd9Sstevel@tonic-gate 		}
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate 	if (bkt_locks_held == 0)
867c478bd9Sstevel@tonic-gate 		(void) printf("\tnone.\n");
877c478bd9Sstevel@tonic-gate 	else
887c478bd9Sstevel@tonic-gate 		(void) printf("\t[%d bucket(s) locked]\n", bkt_locks_held);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static void
clear_buffer_locks(bindhead * bhp)927c478bd9Sstevel@tonic-gate clear_buffer_locks(bindhead * bhp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	int	i;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (query_lock(&bhp->bh_strlock) == 1) {
977c478bd9Sstevel@tonic-gate 		(void) _lwp_mutex_unlock(&bhp->bh_strlock);
987c478bd9Sstevel@tonic-gate 		(void) printf("bh_strlock: cleared\n");
997c478bd9Sstevel@tonic-gate 	}
1007c478bd9Sstevel@tonic-gate 	if (query_lock(&bhp->bh_lock) == 1) {
1017c478bd9Sstevel@tonic-gate 		(void) _lwp_mutex_unlock(&bhp->bh_lock);
1027c478bd9Sstevel@tonic-gate 		(void) printf("bh_lock: cleared\n");
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	for (i = 0; i < bhp->bh_bktcnt; i++) {
1057c478bd9Sstevel@tonic-gate 		if (query_lock(&bhp->bh_bkts[i].bb_lock) == 1) {
1067c478bd9Sstevel@tonic-gate 			(void) _lwp_mutex_unlock(&bhp->bh_bkts[i].bb_lock);
1077c478bd9Sstevel@tonic-gate 			(void) printf("bkt[%d]: lock cleared\n", i);
1087c478bd9Sstevel@tonic-gate 		}
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate static void
set_buffer_locks(bindhead * bhp)1137c478bd9Sstevel@tonic-gate set_buffer_locks(bindhead * bhp)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	int	i;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	for (i = 0; i < bhp->bh_bktcnt; i++)
1187c478bd9Sstevel@tonic-gate 		(void) _lwp_mutex_lock(&bhp->bh_bkts[i].bb_lock);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	(void) _lwp_mutex_lock(&bhp->bh_strlock);
1217c478bd9Sstevel@tonic-gate 	(void) _lwp_mutex_lock(&bhp->bh_lock);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1257c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	int		fd;
1287c478bd9Sstevel@tonic-gate 	char		*fname, *format_string;
1297c478bd9Sstevel@tonic-gate 	bindhead	*bhp, *tmp_bhp;
1307c478bd9Sstevel@tonic-gate 	int		i, c;
1317c478bd9Sstevel@tonic-gate 	int		bflag = 0, pflag = 0, qflag = 0, cflag = 0, sflag = 0;
1327c478bd9Sstevel@tonic-gate 	ulong_t		symcount, callcount;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "bspcq")) != EOF)
1357c478bd9Sstevel@tonic-gate 		switch (c) {
1367c478bd9Sstevel@tonic-gate 		case 'b':
1377c478bd9Sstevel@tonic-gate 			bflag++;
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		case 'p':
1407c478bd9Sstevel@tonic-gate 			pflag++;
1417c478bd9Sstevel@tonic-gate 			break;
1427c478bd9Sstevel@tonic-gate 		case 'q':
1437c478bd9Sstevel@tonic-gate 			qflag++;
1447c478bd9Sstevel@tonic-gate 			break;
1457c478bd9Sstevel@tonic-gate 		case 'c':
1467c478bd9Sstevel@tonic-gate 			cflag++;
1477c478bd9Sstevel@tonic-gate 			break;
1487c478bd9Sstevel@tonic-gate 		case 's':
1497c478bd9Sstevel@tonic-gate 			sflag++;
1507c478bd9Sstevel@tonic-gate 			break;
1517c478bd9Sstevel@tonic-gate 		case '?':
1527c478bd9Sstevel@tonic-gate 			usage();
1537c478bd9Sstevel@tonic-gate 			return (1);
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if (optind == argc) {
1577c478bd9Sstevel@tonic-gate 		usage();
1587c478bd9Sstevel@tonic-gate 		return (1);
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	fname = argv[optind];
1617c478bd9Sstevel@tonic-gate 	if ((fd = open(fname, O_RDWR)) == -1) {
1627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1637c478bd9Sstevel@tonic-gate 		    "dumpbindings: unable to open file: %s\n", fname);
1647c478bd9Sstevel@tonic-gate 		perror("open");
1657c478bd9Sstevel@tonic-gate 		return (1);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	/* LINTED */
1687c478bd9Sstevel@tonic-gate 	if ((bhp = (bindhead *)mmap(0, sizeof (bindhead),
1697c478bd9Sstevel@tonic-gate 	    (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0)) == MAP_FAILED) {
1707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "dumpbind: mmap failed\n");
1717c478bd9Sstevel@tonic-gate 		perror("mmap");
1727c478bd9Sstevel@tonic-gate 		return (1);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (qflag) {
1767c478bd9Sstevel@tonic-gate 		query_buffer_locks(bhp);
1777c478bd9Sstevel@tonic-gate 		return (0);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (cflag) {
1817c478bd9Sstevel@tonic-gate 		clear_buffer_locks(bhp);
1827c478bd9Sstevel@tonic-gate 		return (0);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 	if (sflag) {
1857c478bd9Sstevel@tonic-gate 		set_buffer_locks(bhp);
1867c478bd9Sstevel@tonic-gate 		return (0);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/* LINTED */
1907c478bd9Sstevel@tonic-gate 	if ((tmp_bhp = (bindhead *)mmap(0, bhp->bh_size,
1917c478bd9Sstevel@tonic-gate 	    (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0)) == MAP_FAILED) {
1927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "dumpbind: remap: mmap failed\n");
1937c478bd9Sstevel@tonic-gate 		perror("mmap");
1947c478bd9Sstevel@tonic-gate 		return (1);
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	(void) close(fd);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	(void) munmap((void *)bhp, sizeof (bindhead));
1997c478bd9Sstevel@tonic-gate 	bhp = tmp_bhp;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (pflag)
2027c478bd9Sstevel@tonic-gate 		format_string = "%s|%s|%8d\n";
2037c478bd9Sstevel@tonic-gate 	else {
204*20c1c355SRod Evans 		if (!bflag) {
205*20c1c355SRod Evans 			(void) printf("                           "
206*20c1c355SRod Evans 			    "Bindings Summary Report\n\n"
207*20c1c355SRod Evans 			    "Library                             Symbol"
208*20c1c355SRod Evans 			    "                   Call Count\n"
209*20c1c355SRod Evans 			    "----------------------------------------------"
210*20c1c355SRod Evans 			    "--------------------------\n");
211*20c1c355SRod Evans 		}
2127c478bd9Sstevel@tonic-gate 		format_string = "%-35s %-25s %5d\n";
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	symcount = 0;
2167c478bd9Sstevel@tonic-gate 	callcount = 0;
2177c478bd9Sstevel@tonic-gate 	for (i = 0; i < bhp->bh_bktcnt; i++) {
2187c478bd9Sstevel@tonic-gate 		int		ent_cnt = 0;
2197c478bd9Sstevel@tonic-gate 		binding_entry *	bep;
2207c478bd9Sstevel@tonic-gate 		unsigned int	bep_off = bhp->bh_bkts[i].bb_head;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 		while (bep_off) {
2237c478bd9Sstevel@tonic-gate 			/* LINTED */
2247c478bd9Sstevel@tonic-gate 			bep = (binding_entry *)((char *)bhp + bep_off);
2257c478bd9Sstevel@tonic-gate 			if (!bflag) {
2267c478bd9Sstevel@tonic-gate 				/* LINTED */
2277c478bd9Sstevel@tonic-gate 				(void) printf(format_string,
2287c478bd9Sstevel@tonic-gate 				    (char *)bhp + bep->be_lib_name,
2297c478bd9Sstevel@tonic-gate 				    (char *)bhp + bep->be_sym_name,
2307c478bd9Sstevel@tonic-gate 				    bep->be_count);
2317c478bd9Sstevel@tonic-gate 				symcount++;
2327c478bd9Sstevel@tonic-gate 				callcount += bep->be_count;
2337c478bd9Sstevel@tonic-gate 			}
2347c478bd9Sstevel@tonic-gate 			bep_off = bep->be_next;
2357c478bd9Sstevel@tonic-gate 			ent_cnt++;
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 		if (bflag)
2387c478bd9Sstevel@tonic-gate 			(void) printf("bkt[%d] - %d entries\n", i, ent_cnt);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
241*20c1c355SRod Evans 	if (!bflag && !pflag) {
242*20c1c355SRod Evans 		(void) printf("----------------------------------------------"
243*20c1c355SRod Evans 		    "--------------------------\n"
244*20c1c355SRod Evans 		    "Symbol Count: %lu    Call Count: %lu\n\n",
245*20c1c355SRod Evans 		    symcount, callcount);
246*20c1c355SRod Evans 	}
2477c478bd9Sstevel@tonic-gate 	return (0);
2487c478bd9Sstevel@tonic-gate }
249