view usr/src/cmd/sgs/link_audit/common/dumpbind.c @ 12939:a27c46eb192b

6972234 sgs demo's could use some cleanup
author Rod Evans <Rod.Evans@Sun.COM>
date Tue, 27 Jul 2010 22:49:34 -0700
parents 68f95e015346
children
line wrap: on
line source

/*
 * 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	<stdlib.h>
#include	<unistd.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<sys/lwp.h>
#include	<fcntl.h>
#include	<stdio.h>
#include	<sys/mman.h>
#include	<synch.h>
#include	<errno.h>

#include	"bindings.h"

void
usage()
{
	(void) printf("usage: dumpbind [-pqsc] <bindings.data>\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);
}