sbin/hammer2/cmd_debug.c: Clear errno
[dragonfly.git] / sys / kern / subr_module.c
blob231aabaeca0a7d84d85a48a2673b41e55c7a83b1
1 /*-
2 * Copyright (c) 1998 Michael Smith
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32 #include <sys/sbuf.h>
33 #include <sys/sysctl.h>
35 #include <machine/metadata.h>
38 * Preloaded module support
41 caddr_t preload_metadata;
44 * Search for the preloaded module (name)
46 caddr_t
47 preload_search_by_name(const char *name)
49 caddr_t curp;
50 u_int32_t *hdr;
51 int next;
52 int i;
53 char *scanname;
55 if (preload_metadata == NULL)
56 return(NULL);
58 curp = preload_metadata;
59 for (;;) {
60 hdr = (u_int32_t *)curp;
61 if (hdr[0] == 0 && hdr[1] == 0)
62 break;
65 * Search for a MODINFO_NAME field. the boot loader really
66 * ought to strip the path names
68 if (hdr[0] == MODINFO_NAME) {
69 scanname = curp + sizeof(u_int32_t) * 2;
70 i = strlen(scanname);
71 while (i > 0 && scanname[i-1] != '/')
72 --i;
73 if (strcmp(name, scanname) == 0)
74 return(curp);
75 if (strcmp(name, scanname + i) == 0)
76 return(curp);
78 /* skip to next field */
79 next = sizeof(u_int32_t) * 2 + hdr[1];
80 next = roundup(next, sizeof(u_long));
81 curp += next;
83 return(NULL);
87 * Search for the first preloaded module of (type)
89 caddr_t
90 preload_search_by_type(const char *type)
92 caddr_t curp, lname;
93 u_int32_t *hdr;
94 int next;
96 if (preload_metadata != NULL) {
98 curp = preload_metadata;
99 lname = NULL;
100 for (;;) {
101 hdr = (u_int32_t *)curp;
102 if (hdr[0] == 0 && hdr[1] == 0)
103 break;
105 /* remember the start of each record */
106 if (hdr[0] == MODINFO_NAME)
107 lname = curp;
109 /* Search for a MODINFO_TYPE field */
110 if ((hdr[0] == MODINFO_TYPE) &&
111 !strcmp(type, curp + sizeof(u_int32_t) * 2))
112 return(lname);
114 /* skip to next field */
115 next = sizeof(u_int32_t) * 2 + hdr[1];
116 next = roundup(next, sizeof(u_long));
117 curp += next;
120 return(NULL);
124 * Walk through the preloaded module list
126 caddr_t
127 preload_search_next_name(caddr_t base)
129 caddr_t curp;
130 u_int32_t *hdr;
131 int next;
133 if (preload_metadata != NULL) {
135 /* Pick up where we left off last time */
136 if (base) {
137 /* skip to next field */
138 curp = base;
139 hdr = (u_int32_t *)curp;
140 next = sizeof(u_int32_t) * 2 + hdr[1];
141 next = roundup(next, sizeof(u_long));
142 curp += next;
143 } else
144 curp = preload_metadata;
146 for (;;) {
147 hdr = (u_int32_t *)curp;
148 if (hdr[0] == 0 && hdr[1] == 0)
149 break;
151 /* Found a new record? */
152 if (hdr[0] == MODINFO_NAME)
153 return curp;
155 /* skip to next field */
156 next = sizeof(u_int32_t) * 2 + hdr[1];
157 next = roundup(next, sizeof(u_long));
158 curp += next;
161 return(NULL);
165 * Given a preloaded module handle (mod), return a pointer
166 * to the data for the attribute (inf).
168 caddr_t
169 preload_search_info(caddr_t mod, int inf)
171 caddr_t curp;
172 u_int32_t *hdr;
173 u_int32_t type = 0;
174 int next;
176 curp = mod;
177 for (;;) {
178 hdr = (u_int32_t *)curp;
179 /* end of module data? */
180 if (hdr[0] == 0 && hdr[1] == 0)
181 break;
183 * We give up once we've looped back to what we were looking at
184 * first - this should normally be a MODINFO_NAME field.
186 if (type == 0) {
187 type = hdr[0];
188 } else {
189 if (hdr[0] == type)
190 break;
194 * Attribute match? Return pointer to data.
195 * Consumer may safely assume that size value preceeds
196 * data.
198 if (hdr[0] == inf)
199 return(curp + (sizeof(u_int32_t) * 2));
201 /* skip to next field */
202 next = sizeof(u_int32_t) * 2 + hdr[1];
203 next = roundup(next, sizeof(u_long));
204 curp += next;
206 return(NULL);
210 * Delete a preload record by path name.
212 void
213 preload_delete_name(const char *name)
215 caddr_t curp;
216 u_int32_t *hdr;
217 int next;
218 int clearing;
220 if (preload_metadata != NULL) {
221 clearing = 0;
222 curp = preload_metadata;
223 for (;;) {
224 hdr = (u_int32_t *)curp;
225 if (hdr[0] == 0 && hdr[1] == 0)
226 break;
228 /* Search for a MODINFO_NAME field */
229 if (hdr[0] == MODINFO_NAME) {
230 if (strcmp(name, curp + sizeof(u_int32_t) * 2) == 0)
231 clearing = 1; /* start clearing */
232 else if (clearing)
233 clearing = 0; /* at next module now, stop clearing */
235 if (clearing)
236 hdr[0] = MODINFO_EMPTY;
238 /* skip to next field */
239 next = sizeof(u_int32_t) * 2 + hdr[1];
240 next = roundup(next, sizeof(u_long));
241 curp += next;
246 /* Called from hammer_time() on pc64. Convert physical pointers to kvm. Sigh. */
247 void
248 preload_bootstrap_relocate(vm_offset_t offset)
250 caddr_t curp;
251 u_int32_t *hdr;
252 vm_offset_t *ptr;
253 int next;
255 if (preload_metadata != NULL) {
257 curp = preload_metadata;
258 for (;;) {
259 hdr = (u_int32_t *)curp;
260 if (hdr[0] == 0 && hdr[1] == 0)
261 break;
263 /* Deal with the ones that we know we have to fix */
264 switch (hdr[0]) {
265 case MODINFO_ADDR:
266 case MODINFO_METADATA|MODINFOMD_SSYM:
267 case MODINFO_METADATA|MODINFOMD_ESYM:
268 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
269 *ptr += offset;
270 break;
272 /* The rest is beyond us for now */
274 /* skip to next field */
275 next = sizeof(u_int32_t) * 2 + hdr[1];
276 next = roundup(next, sizeof(u_long));
277 curp += next;
283 * Parse the modinfo type and append to the sbuf.
285 static void
286 preload_modinfo_type(struct sbuf *sbp, int type)
288 if ((type & MODINFO_METADATA) == 0) {
289 switch (type) {
290 case MODINFO_END:
291 sbuf_cat(sbp, "MODINFO_END");
292 break;
293 case MODINFO_NAME:
294 sbuf_cat(sbp, "MODINFO_NAME");
295 break;
296 case MODINFO_TYPE:
297 sbuf_cat(sbp, "MODINFO_TYPE");
298 break;
299 case MODINFO_ADDR:
300 sbuf_cat(sbp, "MODINFO_ADDR");
301 break;
302 case MODINFO_SIZE:
303 sbuf_cat(sbp, "MODINFO_SIZE");
304 break;
305 case MODINFO_EMPTY:
306 sbuf_cat(sbp, "MODINFO_EMPTY");
307 break;
308 case MODINFO_ARGS:
309 sbuf_cat(sbp, "MODINFO_ARGS");
310 break;
311 default:
312 sbuf_cat(sbp, "unrecognized modinfo attribute");
315 return;
318 sbuf_cat(sbp, "MODINFO_METADATA | ");
319 switch (type & ~MODINFO_METADATA) {
320 case MODINFOMD_ELFHDR:
321 sbuf_cat(sbp, "MODINFOMD_ELFHDR");
322 break;
323 case MODINFOMD_SSYM:
324 sbuf_cat(sbp, "MODINFOMD_SSYM");
325 break;
326 case MODINFOMD_ESYM:
327 sbuf_cat(sbp, "MODINFOMD_ESYM");
328 break;
329 case MODINFOMD_DYNAMIC:
330 sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
331 break;
332 case MODINFOMD_ENVP:
333 sbuf_cat(sbp, "MODINFOMD_ENVP");
334 break;
335 case MODINFOMD_HOWTO:
336 sbuf_cat(sbp, "MODINFOMD_HOWTO");
337 break;
338 case MODINFOMD_KERNEND:
339 sbuf_cat(sbp, "MODINFOMD_KERNEND");
340 break;
341 case MODINFOMD_SHDR:
342 sbuf_cat(sbp, "MODINFOMD_SHDR");
343 break;
344 case MODINFOMD_FW_HANDLE:
345 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
346 break;
347 case MODINFOMD_SMAP:
348 sbuf_cat(sbp, "MODINFOMD_SMAP");
349 break;
350 case MODINFOMD_EFI_MAP:
351 sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
352 break;
353 case MODINFOMD_EFI_FB:
354 sbuf_cat(sbp, "MODINFOMD_EFI_FB");
355 break;
356 default:
357 sbuf_cat(sbp, "unrecognized metadata type");
362 * Print the modinfo value, depending on type.
364 static void
365 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
367 switch (type) {
368 case MODINFO_NAME:
369 case MODINFO_TYPE:
370 case MODINFO_ARGS:
371 sbuf_printf(sbp, "%s", (char *)bptr);
372 break;
373 case MODINFO_SIZE:
374 sbuf_printf(sbp, "%lu", *(u_long *)bptr);
375 break;
376 case MODINFO_ADDR:
377 case MODINFO_METADATA | MODINFOMD_SSYM:
378 case MODINFO_METADATA | MODINFOMD_ESYM:
379 case MODINFO_METADATA | MODINFOMD_DYNAMIC:
380 case MODINFO_METADATA | MODINFOMD_KERNEND:
381 case MODINFO_METADATA | MODINFOMD_ENVP:
382 case MODINFO_METADATA | MODINFOMD_SMAP:
383 case MODINFO_METADATA | MODINFOMD_EFI_FB:
384 sbuf_printf(sbp, "0x%016lx", *(vm_offset_t *)bptr);
385 break;
386 case MODINFO_METADATA | MODINFOMD_HOWTO:
387 sbuf_printf(sbp, "0x%08x", *bptr);
388 break;
389 case MODINFO_METADATA | MODINFOMD_SHDR:
390 case MODINFO_METADATA | MODINFOMD_ELFHDR:
391 case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
392 case MODINFO_METADATA | MODINFOMD_EFI_MAP:
393 /* Don't print data buffers. */
394 sbuf_cat(sbp, "buffer contents omitted");
395 break;
396 default:
397 break;
401 static void
402 preload_dump_internal(struct sbuf *sbp)
404 uint32_t *bptr, type, len;
406 sbuf_putc(sbp, '\n');
408 /* Iterate through the TLV-encoded sections. */
409 bptr = (uint32_t *)preload_metadata;
410 while (bptr[0] != MODINFO_END) {
411 sbuf_printf(sbp, " %p:\n", bptr);
413 type = *bptr++;
414 sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
415 preload_modinfo_type(sbp, type);
416 sbuf_putc(sbp, '\n');
418 len = *bptr++;
419 sbuf_printf(sbp, "\tlen:\t%u\n", len);
421 sbuf_cat(sbp, "\tvalue:\t");
422 preload_modinfo_value(sbp, bptr, type, len);
423 sbuf_putc(sbp, '\n');
425 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
429 static int
430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
432 struct sbuf sb;
433 int error;
435 if (preload_metadata == NULL)
436 return (EINVAL);
438 sbuf_new_for_sysctl(&sb, NULL, 512, req);
439 preload_dump_internal(&sb);
441 error = sbuf_finish(&sb);
442 sbuf_delete(&sb);
444 return (error);
447 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
448 CTLTYPE_STRING | CTLFLAG_RD,
449 NULL, 0, sysctl_preload_dump, "A",
450 "pretty-print the bootloader metadata");