1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <inttypes.h> 31 #include <stdio.h> 32 #include <stddef.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/modctl.h> 36 #include <sys/errno.h> 37 38 static int wide; 39 static int count = 0; 40 static int first_mod = 1; 41 42 /* 43 * When printing module load addresses on 32-bit kernels, the 8 hex 44 * character field width is obviously adequate. On sparcv9 kernels 45 * solely by virtue of the choice of code model enabled by the separate 46 * kernel context, the text addresses are currently in the lower 4G 47 * address range, and so -still- fit in 8 hex characters. 48 * 49 * However, amd64 kernels live at the top of the 64-bit address space, and 50 * so as to be honest about the addresses (and since this is a tool for 51 * humans to parse), we have to print out a 16 hex character address. 52 * 53 * We assume that we will print out all 16 hex characters on future 54 * 64-bit kernel ports too. 55 */ 56 static const char header[] = 57 " Id " 58 #if defined(_LP64) && !defined(__sparcv9) 59 " " 60 #endif 61 "Loadaddr Size Info Rev Module Name\n"; 62 63 static char *cheader = 64 " Id Loadcnt Module Name State\n"; 65 66 67 static void usage(); 68 static void print_info(struct modinfo *mi); 69 static void print_cinfo(struct modinfo *mi); 70 71 /* 72 * These functions are in modsubr.c 73 */ 74 void fatal(char *fmt, ...); 75 void error(char *fmt, ...); 76 77 /* 78 * Display information of all loaded modules 79 */ 80 int 81 main(int argc, char *argv[]) 82 { 83 struct modinfo modinfo; 84 int info_all = 1; 85 int id; 86 int opt; 87 88 id = -1; /* assume we're getting all loaded modules */ 89 90 while ((opt = getopt(argc, argv, "i:wc")) != EOF) { 91 switch (opt) { 92 case 'i': 93 if (sscanf(optarg, "%d", &id) != 1) 94 fatal("Invalid id %s\n", optarg); 95 if (id == -1) 96 id = 0; 97 info_all = 0; 98 break; 99 case 'w': 100 wide++; 101 break; 102 case 'c': 103 count++; 104 break; 105 case '?': 106 default: 107 usage(); 108 break; 109 } 110 } 111 112 113 /* 114 * Next id of -1 means we're getting info on all modules. 115 */ 116 modinfo.mi_id = modinfo.mi_nextid = id; 117 modinfo.mi_info = (info_all) ? MI_INFO_ALL : MI_INFO_ONE; 118 119 if (count) 120 modinfo.mi_info |= MI_INFO_CNT; 121 122 do { 123 /* 124 * Get module information. 125 * If modinfo.mi_nextid == -1, get info about the 126 * next installed module with id > "id." 127 * Otherwise, get info about the module with id == "id." 128 */ 129 if (modctl(MODINFO, id, &modinfo) < 0) { 130 if (!info_all) 131 error("can't get module information"); 132 break; 133 } 134 135 if (first_mod) { 136 first_mod = 0; 137 (void) printf(count ? cheader : header); 138 } 139 if (count) 140 print_cinfo(&modinfo); 141 else 142 print_info(&modinfo); 143 /* 144 * If we're getting info about all modules, the next one 145 * we want is the one with an id greater than this one. 146 */ 147 id = modinfo.mi_id; 148 } while (info_all); 149 150 return (0); 151 } 152 153 /* 154 * Display loadcounts. 155 */ 156 static void 157 print_cinfo(struct modinfo *mi) 158 { 159 (void) printf("%3d %10d %-32s", mi->mi_id, mi->mi_loadcnt, mi->mi_name); 160 (void) printf(" %s/%s\n", 161 mi->mi_state & MI_LOADED ? "LOADED" : "UNLOADED", 162 mi->mi_state & MI_INSTALLED ? "INSTALLED" : "UNINSTALLED"); 163 } 164 165 /* 166 * Display info about a loaded module. 167 * 168 */ 169 static void 170 print_info(struct modinfo *mi) 171 { 172 int n, p0; 173 char namebuf[256]; 174 175 for (n = 0; n < MODMAXLINK; n++) { 176 if (n > 0 && mi->mi_msinfo[n].msi_linkinfo[0] == '\0') 177 break; 178 179 (void) printf("%3d ", mi->mi_id); 180 #if defined(_LP64) && !defined(__sparcv9) 181 (void) printf("%16lx ", (uintptr_t)mi->mi_base); 182 #else 183 (void) printf("%8lx ", (uintptr_t)mi->mi_base); 184 #endif 185 (void) printf("%6x ", mi->mi_size); 186 187 p0 = mi->mi_msinfo[n].msi_p0; 188 189 if (p0 != -1) 190 (void) printf("%3d ", p0); 191 else 192 (void) printf(" - "); 193 194 (void) printf(" %d ", mi->mi_rev); 195 196 mi->mi_name[MODMAXNAMELEN - 1] = '\0'; 197 mi->mi_msinfo[n].msi_linkinfo[MODMAXNAMELEN - 1] = '\0'; 198 199 if (wide) { 200 (void) printf("%s (%s)\n", mi->mi_name, 201 mi->mi_msinfo[n].msi_linkinfo); 202 } else { 203 /* snprintf(3c) will always append a null character */ 204 (void) snprintf(namebuf, sizeof (namebuf), "%s (%s)", 205 mi->mi_name, mi->mi_msinfo[n].msi_linkinfo); 206 #if defined(_LP64) && !defined(__sparcv9) 207 (void) printf("%.43s\n", namebuf); 208 #else 209 (void) printf("%.51s\n", namebuf); 210 #endif 211 } 212 } 213 } 214 215 static void 216 usage() 217 { 218 fatal("usage: modinfo [-w] [-c] [-i module-id]\n"); 219 } 220