OpenSolaris_b135/cmd/modload/modinfo.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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.
 */

#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/modctl.h>
#include <sys/errno.h>

static int wide;
static int count = 0;
static int first_mod = 1;

/*
 * When printing module load addresses on 32-bit kernels, the 8 hex
 * character field width is obviously adequate. On sparcv9 kernels
 * solely by virtue of the choice of code model enabled by the separate
 * kernel context, the text addresses are currently in the lower 4G
 * address range, and so -still- fit in 8 hex characters.
 *
 * However, amd64 kernels live at the top of the 64-bit address space, and
 * so as to be honest about the addresses (and since this is a tool for
 * humans to parse), we have to print out a 16 hex character address.
 *
 * We assume that we will print out all 16 hex characters on future
 * 64-bit kernel ports too.
 */
static const char header[] =
	" Id "
#if defined(_LP64) && !defined(__sparcv9)
	"        "
#endif
	"Loadaddr   Size Info Rev Module Name\n";

static char *cheader  =
	" Id    Loadcnt Module Name                            State\n";


static void usage();
static void print_info(struct modinfo *mi);
static void print_cinfo(struct modinfo *mi);

/*
 * These functions are in modsubr.c
 */
void fatal(char *fmt, ...);
void error(char *fmt, ...);

/*
 * Display information of all loaded modules
 */
int
main(int argc, char *argv[])
{
	struct modinfo modinfo;
	int info_all = 1;
	int id;
	int opt;

	id = -1;	/* assume we're getting all loaded modules */

	while ((opt = getopt(argc, argv, "i:wc")) != EOF) {
		switch (opt) {
		case 'i':
			if (sscanf(optarg, "%d", &id) != 1)
				fatal("Invalid id %s\n", optarg);
			if (id == -1)
				id = 0;
			info_all = 0;
			break;
		case 'w':
			wide++;
			break;
		case 'c':
			count++;
			break;
		case '?':
		default:
			usage();
			break;
		}
	}


	/*
	 * Next id of -1 means we're getting info on all modules.
	 */
	modinfo.mi_id = modinfo.mi_nextid = id;
	modinfo.mi_info = (info_all) ? MI_INFO_ALL : MI_INFO_ONE;

	if (count)
		modinfo.mi_info |= MI_INFO_CNT;

	do {
		/*
		 * Get module information.
		 * If modinfo.mi_nextid == -1, get info about the
		 * next installed module with id > "id."
		 * Otherwise, get info about the module with id == "id."
		 */
		if (modctl(MODINFO, id, &modinfo) < 0) {
			if (!info_all)
				error("can't get module information");
			break;
		}

		if (first_mod) {
			first_mod = 0;
			(void) printf("%s", count ? cheader : header);
		}
		if (count)
			print_cinfo(&modinfo);
		else
			print_info(&modinfo);
		/*
		 * If we're getting info about all modules, the next one
		 * we want is the one with an id greater than this one.
		 */
		id = modinfo.mi_id;
	} while (info_all);

	return (0);
}

/*
 * Display loadcounts.
 */
static void
print_cinfo(struct modinfo *mi)
{
	(void) printf("%3d %10d %-32s", mi->mi_id, mi->mi_loadcnt, mi->mi_name);
	(void) printf(" %s/%s\n",
	    mi->mi_state & MI_LOADED ? "LOADED" : "UNLOADED",
	    mi->mi_state & MI_INSTALLED ? "INSTALLED" : "UNINSTALLED");
}

/*
 * Display info about a loaded module.
 *
 * The sparc kernel resides in its own address space, with modules
 * loaded at low addresses.  The low 32-bits of a module's base
 * address is sufficient but does put a cap at 4gb here.
 * The x86 64-bit kernel is loaded in high memory with the full
 * address provided.
 */
static void
print_info(struct modinfo *mi)
{
	int n, p0;
	char namebuf[256];

	for (n = 0; n < MODMAXLINK; n++) {
		if (n > 0 && mi->mi_msinfo[n].msi_linkinfo[0] == '\0')
			break;

		(void) printf("%3d ", mi->mi_id);
#if defined(_LP64) && !defined(__sparcv9)
		(void) printf("%16lx ", (uintptr_t)mi->mi_base);
#elif defined(_LP64)
		(void) printf("%8lx ", (uintptr_t)mi->mi_base);
#else
		(void) printf("%8x ", (uintptr_t)mi->mi_base);
#endif
#if defined(_LP64)
		(void) printf("%6lx ", mi->mi_size);
#else
		(void) printf("%6x ", mi->mi_size);
#endif

		p0 = mi->mi_msinfo[n].msi_p0;

		if (p0 != -1)
			(void) printf("%3d ", p0);
		else
			(void) printf("  - ");

		(void) printf("  %d  ", mi->mi_rev);

		mi->mi_name[MODMAXNAMELEN - 1] = '\0';
		mi->mi_msinfo[n].msi_linkinfo[MODMAXNAMELEN - 1] = '\0';

		if (wide) {
			(void) printf("%s (%s)\n", mi->mi_name,
			    mi->mi_msinfo[n].msi_linkinfo);
		} else {
			/* snprintf(3c) will always append a null character */
			(void) snprintf(namebuf, sizeof (namebuf), "%s (%s)",
			    mi->mi_name, mi->mi_msinfo[n].msi_linkinfo);
#if defined(_LP64) && !defined(__sparcv9)
			(void) printf("%.43s\n", namebuf);
#else
			(void) printf("%.51s\n", namebuf);
#endif
		}
	}
}

static void
usage()
{
	fatal("usage:  modinfo [-w] [-c] [-i module-id]\n");
}