/* * 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); }