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
main(int argc,char * argv[])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
print_cinfo(struct modinfo * mi)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
print_info(struct modinfo * mi)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
usage()224 usage()
225 {
226 fatal("usage: modinfo [-w] [-c] [-i module-id]\n");
227 }
228