xref: /illumos-gate/usr/src/cmd/modload/modinfo.c (revision 3db86aab)
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