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