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