Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/subr_module.c
Show All 26 Lines | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
#include <sys/sbuf.h> | |||||
#include <sys/sysctl.h> | |||||
#include <machine/metadata.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
/* | /* | ||||
* Preloaded module support | * Preloaded module support | ||||
*/ | */ | ||||
vm_offset_t preload_addr_relocate = 0; | vm_offset_t preload_addr_relocate = 0; | ||||
▲ Show 20 Lines • Show All 255 Lines • ▼ Show 20 Lines | break; | ||||
/* skip to next field */ | /* skip to next field */ | ||||
next = sizeof(uint32_t) * 2 + hdr[1]; | next = sizeof(uint32_t) * 2 + hdr[1]; | ||||
next = roundup(next, sizeof(u_long)); | next = roundup(next, sizeof(u_long)); | ||||
curp += next; | curp += next; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | |||||
* Parse the modinfo type and append to the provided sbuf. | |||||
*/ | |||||
static void | |||||
preload_modinfo_type(struct sbuf *sbp, int type) | |||||
{ | |||||
if ((type & MODINFO_METADATA) == 0) { | |||||
switch (type) { | |||||
case MODINFO_END: | |||||
sbuf_cat(sbp, "MODINFO_END"); | |||||
break; | |||||
case MODINFO_NAME: | |||||
sbuf_cat(sbp, "MODINFO_NAME"); | |||||
break; | |||||
case MODINFO_TYPE: | |||||
sbuf_cat(sbp, "MODINFO_TYPE"); | |||||
break; | |||||
case MODINFO_ADDR: | |||||
sbuf_cat(sbp, "MODINFO_ADDR"); | |||||
break; | |||||
case MODINFO_SIZE: | |||||
sbuf_cat(sbp, "MODINFO_SIZE"); | |||||
break; | |||||
case MODINFO_EMPTY: | |||||
sbuf_cat(sbp, "MODINFO_EMPTY"); | |||||
break; | |||||
case MODINFO_ARGS: | |||||
sbuf_cat(sbp, "MODINFO_ARGS"); | |||||
break; | |||||
default: | |||||
sbuf_cat(sbp, "???"); | |||||
tsoome: It would be better to output something like "unknown modinfo attribute" | |||||
} | |||||
return; | |||||
} | |||||
sbuf_cat(sbp, "MODINFO_METADATA | "); | |||||
switch (type & ~MODINFO_METADATA) { | |||||
case MODINFOMD_ELFHDR: | |||||
sbuf_cat(sbp, "MODINFOMD_ELFHDR"); | |||||
break; | |||||
case MODINFOMD_SSYM: | |||||
sbuf_cat(sbp, "MODINFOMD_SSYM"); | |||||
break; | |||||
case MODINFOMD_ESYM: | |||||
sbuf_cat(sbp, "MODINFOMD_ESYM"); | |||||
break; | |||||
case MODINFOMD_DYNAMIC: | |||||
sbuf_cat(sbp, "MODINFOMD_DYNAMIC"); | |||||
break; | |||||
case MODINFOMD_ENVP: | |||||
sbuf_cat(sbp, "MODINFOMD_ENVP"); | |||||
break; | |||||
case MODINFOMD_HOWTO: | |||||
sbuf_cat(sbp, "MODINFOMD_HOWTO"); | |||||
break; | |||||
case MODINFOMD_KERNEND: | |||||
sbuf_cat(sbp, "MODINFOMD_KERNEND"); | |||||
break; | |||||
case MODINFOMD_SHDR: | |||||
sbuf_cat(sbp, "MODINFOMD_SHDR"); | |||||
break; | |||||
case MODINFOMD_CTORS_ADDR: | |||||
sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR"); | |||||
break; | |||||
case MODINFOMD_CTORS_SIZE: | |||||
sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE"); | |||||
break; | |||||
case MODINFOMD_FW_HANDLE: | |||||
sbuf_cat(sbp, "MODINFOMD_FW_HANDLE"); | |||||
break; | |||||
case MODINFOMD_KEYBUF: | |||||
sbuf_cat(sbp, "MODINFOMD_KEYBUF"); | |||||
break; | |||||
#ifdef MODINFOMD_SMAP | |||||
case MODINFOMD_SMAP: | |||||
sbuf_cat(sbp, "MODINFOMD_SMAP"); | |||||
break; | |||||
#endif | |||||
#ifdef MODINFOMD_SMAP_XATTR | |||||
case MODINFOMD_SMAP_XATTR: | |||||
sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR"); | |||||
break; | |||||
#endif | |||||
#ifdef MODINFOMD_DTBP | |||||
case MODINFOMD_DTBP: | |||||
sbuf_cat(sbp, "MODINFOMD_DTBP"); | |||||
break; | |||||
#endif | |||||
#ifdef MODINFOMD_EFI_MAP | |||||
case MODINFOMD_EFI_MAP: | |||||
sbuf_cat(sbp, "MODINFOMD_EFI_MAP"); | |||||
break; | |||||
#endif | |||||
#ifdef MODINFOMD_EFI_FB | |||||
case MODINFOMD_EFI_FB: | |||||
sbuf_cat(sbp, "MODINFOMD_EFI_FB"); | |||||
break; | |||||
#endif | |||||
#ifdef MODINFOMD_MODULEP | |||||
case MODINFOMD_MODULEP: | |||||
sbuf_cat(sbp, "MODINFOMD_MODULEP"); | |||||
break; | |||||
#endif | |||||
default: | |||||
sbuf_cat(sbp, "???"); | |||||
tsoomeUnsubmitted Not Done Inline Actionsit would be better to output something like "unknown modinfo metadata type" tsoome: it would be better to output something like "unknown modinfo metadata type" | |||||
mhorneAuthorUnsubmitted Done Inline ActionsThe output will appear something like: 0xffffffff8299a068: type: (0x9004) MODINFO_METADATA | unrecognized metadata type mhorne: The output will appear something like:
```
0xffffffff8299a068:
type: (0x9004)… | |||||
} | |||||
} | |||||
/* | |||||
* Print the modinfo value, depending on type. | |||||
*/ | |||||
static void | |||||
preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len) | |||||
{ | |||||
#ifdef __LP64__ | |||||
#define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%016lx", o); | |||||
#else | |||||
#define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%08lx", o); | |||||
#endif | |||||
switch (type) { | |||||
case MODINFO_NAME: | |||||
case MODINFO_TYPE: | |||||
case MODINFO_ARGS: | |||||
sbuf_printf(sbp, "%s", (char *)bptr); | |||||
break; | |||||
case MODINFO_SIZE: | |||||
case MODINFO_METADATA | MODINFOMD_CTORS_SIZE: | |||||
sbuf_printf(sbp, "%lu", *(u_long *)bptr); | |||||
break; | |||||
case MODINFO_ADDR: | |||||
case MODINFO_METADATA | MODINFOMD_SSYM: | |||||
case MODINFO_METADATA | MODINFOMD_ESYM: | |||||
case MODINFO_METADATA | MODINFOMD_DYNAMIC: | |||||
case MODINFO_METADATA | MODINFOMD_KERNEND: | |||||
case MODINFO_METADATA | MODINFOMD_ENVP: | |||||
case MODINFO_METADATA | MODINFOMD_CTORS_ADDR: | |||||
#ifdef MODINFOMD_SMAP | |||||
case MODINFO_METADATA | MODINFOMD_SMAP: | |||||
#endif | |||||
#ifdef MODINFOMD_SMAP_XATTR | |||||
case MODINFO_METADATA | MODINFOMD_SMAP_XATTR: | |||||
#endif | |||||
#ifdef MODINFOMD_DTBP | |||||
case MODINFO_METADATA | MODINFOMD_DTBP: | |||||
#endif | |||||
#ifdef MODINFOMD_EFI_FB | |||||
case MODINFO_METADATA | MODINFOMD_EFI_FB: | |||||
#endif | |||||
sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr); | |||||
break; | |||||
case MODINFO_METADATA | MODINFOMD_HOWTO: | |||||
sbuf_printf(sbp, "0x%08x", *bptr); | |||||
break; | |||||
case MODINFO_METADATA | MODINFOMD_SHDR: | |||||
case MODINFO_METADATA | MODINFOMD_ELFHDR: | |||||
case MODINFO_METADATA | MODINFOMD_FW_HANDLE: | |||||
case MODINFO_METADATA | MODINFOMD_KEYBUF: | |||||
#ifdef MODINFOMD_EFI_MAP | |||||
case MODINFO_METADATA | MODINFOMD_EFI_MAP: | |||||
#endif | |||||
/* Don't print data buffers. */ | |||||
sbuf_cat(sbp, "buffer contents omitted"); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
#undef sbuf_print_vmoffset | |||||
} | |||||
static void | |||||
preload_dump_internal(struct sbuf *sbp) | |||||
{ | |||||
uint32_t *bptr, type, len; | |||||
KASSERT(preload_metadata != NULL, | |||||
("%s called without setting up preload_metadata", __func__)); | |||||
/* | |||||
* Iterate through the TLV-encoded sections. | |||||
*/ | |||||
bptr = (uint32_t *)preload_metadata; | |||||
sbuf_putc(sbp, '\n'); | |||||
while (bptr[0] != MODINFO_END || bptr[0] != MODINFO_END) { | |||||
sbuf_printf(sbp, " %p:\n", bptr); | |||||
type = *bptr++; | |||||
len = *bptr++; | |||||
sbuf_printf(sbp, "\ttype:\t(%#04x) ", type); | |||||
preload_modinfo_type(sbp, type); | |||||
sbuf_putc(sbp, '\n'); | |||||
sbuf_printf(sbp, "\tlen:\t%u\n", len); | |||||
sbuf_cat(sbp, "\tvalue:\t"); | |||||
preload_modinfo_value(sbp, bptr, type, len); | |||||
sbuf_putc(sbp, '\n'); | |||||
bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t); | |||||
} | |||||
} | |||||
/* | |||||
* Print the preloaded data to the console. Called from the machine-dependent | |||||
* initialization routines, e.g. hammer_time(). | |||||
*/ | |||||
void | |||||
preload_dump(void) | |||||
{ | |||||
char buf[512]; | |||||
struct sbuf sb; | |||||
/* | |||||
* This function is expected to be called before malloc is available, | |||||
* so use a static buffer and struct sbuf. | |||||
*/ | |||||
sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); | |||||
sbuf_set_drain(&sb, sbuf_printf_drain, NULL); | |||||
preload_dump_internal(&sb); | |||||
sbuf_finish(&sb); | |||||
sbuf_delete(&sb); | |||||
} | |||||
static int | |||||
sysctl_preload_dump(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct sbuf sb; | |||||
int error; | |||||
if (preload_metadata == NULL) | |||||
return (EINVAL); | |||||
sbuf_new_for_sysctl(&sb, NULL, 512, req); | |||||
preload_dump_internal(&sb); | |||||
error = sbuf_finish(&sb); | |||||
sbuf_delete(&sb); | |||||
return (error); | |||||
} | |||||
SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo, | |||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, | |||||
NULL, 0, sysctl_preload_dump, "A", | |||||
"pretty-print the bootloader metadata"); |
It would be better to output something like "unknown modinfo attribute"