#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/mach_host.h>
static const char * progname = "(unknown)";
static int kmod_compare(const void * a, const void * b);
static int kmod_ref_compare(const void * a, const void * b);
static kmod_info_t * kmod_lookup(
kmod_info_t * kmods,
unsigned int kmod_count,
int kmod_id);
static void usage(int level);
int main(int argc, const char * argv[])
{
int exit_code = 0;
int optchar = 0;
kern_return_t mach_result = KERN_SUCCESS;
port_t host_port = PORT_NULL;
kmod_info_t * kmod_list;
int kmod_bytecount; int kmod_count;
kmod_info_t * this_kmod;
kmod_reference_t * kmod_ref;
int ref_count;
int i, j;
char * kext_id = 0; int skip_kernel_comps = 0; int print_header = 1;
if (argv[0]) {
progname = argv[0];
}
while ((optchar = getopt(argc, (char * const *)argv, "b:kl")) != -1) {
switch (optchar) {
case 'b':
kext_id = optarg;
break;
case 'k':
skip_kernel_comps = 1;
break;
case 'l':
print_header = 0;
break;
default:
usage(0);
exit_code = 1;
goto finish;
}
}
argc -= optind;
argv += optind;
if (argc != 0) {
usage(0);
exit_code = 1;
goto finish;
}
host_port = mach_host_self();
mach_result = kmod_get_info(host_port, (void *)&kmod_list,
&kmod_bytecount);
if (mach_result != KERN_SUCCESS) {
fprintf(stderr,
"%s: couldn't get list of loaded kexts from kernel - %s\n",
progname, mach_error_string(mach_result));
exit_code = 1;
goto finish;
}
this_kmod = kmod_list;
kmod_count = 0;
while (this_kmod) {
kmod_count++;
this_kmod = (this_kmod->next) ? (this_kmod + 1) : 0;
}
this_kmod = kmod_list;
kmod_ref = (kmod_reference_t *)(kmod_list + kmod_count);
while (this_kmod) {
ref_count = (int)this_kmod->reference_list;
if (ref_count) {
this_kmod->reference_list = kmod_ref;
for (i = 0; i < ref_count; i++) {
int foundit = 0;
for (j = 0; j < kmod_count; j++) {
if (kmod_ref->info == kmod_list[j].next) {
kmod_ref->info = (kmod_info_t *)kmod_list[j].id;
foundit++;
break;
}
}
if (!foundit) {
kmod_ref->info =
(kmod_info_t *)kmod_list[kmod_count - 1].id;
}
kmod_ref++;
}
qsort(this_kmod->reference_list, ref_count,
sizeof(kmod_reference_t), kmod_ref_compare);
for (i = 0; i < ref_count - 1; i++) {
this_kmod->reference_list[i].next =
&this_kmod->reference_list[i+1];
}
this_kmod->reference_list[ref_count - 1].next = 0;
}
this_kmod = (this_kmod->next) ? (this_kmod + 1) : 0;
}
if (print_header) {
printf("Index Refs Address Size Wired "
"Name (Version) <Linked Against>\n");
}
if (!kmod_count) {
goto finish;
}
qsort(kmod_list, kmod_count, sizeof(kmod_info_t), kmod_compare);
if (kext_id) {
this_kmod = &kmod_list[0];
int match_count = 0;
for (i = 0; i < kmod_count; i++, this_kmod++) {
if (this_kmod->name && !strcmp(this_kmod->name, kext_id)) {
kmod_list[match_count++] = *this_kmod;
}
}
kmod_count = match_count;
}
this_kmod = kmod_list;
for (i=0; i < kmod_count; i++, this_kmod++) {
if (skip_kernel_comps && !this_kmod->size && !kext_id) {
continue;
}
printf("%5d %4d %-10p %-10p %-10p %s (%s)",
this_kmod->id,
this_kmod->reference_count,
(void *)this_kmod->address,
(void *)this_kmod->size,
(void *)(this_kmod->size - this_kmod->hdr_size),
this_kmod->name,
this_kmod->version);
kmod_ref = this_kmod->reference_list;
if (kmod_ref) {
int printed_brace = 0;
while (kmod_ref) {
kmod_info_t * ref_info =
kmod_lookup(kmod_list, kmod_count, (int)kmod_ref->info);
if (ref_info && (!skip_kernel_comps || ref_info->address)) {
printf(" %s%d", !printed_brace ? "<" : "",
(int)kmod_ref->info);
printed_brace = 1;
}
kmod_ref = kmod_ref->next;
}
if (printed_brace) {
printf(">");
}
}
printf("\n");
}
finish:
if (PORT_NULL != host_port) {
mach_port_deallocate(mach_task_self(), host_port);
}
if (kmod_list) {
vm_deallocate(mach_task_self(), (vm_address_t)kmod_list,
kmod_bytecount);
}
exit(exit_code);
return exit_code;
}
static int kmod_compare(const void * a, const void * b)
{
kmod_info_t * k1 = (kmod_info_t *)a;
kmod_info_t * k2 = (kmod_info_t *)b;
return (k1->id - k2->id);
}
static int kmod_ref_compare(const void * a, const void * b)
{
kmod_reference_t * r1 = (kmod_reference_t *)a;
kmod_reference_t * r2 = (kmod_reference_t *)b;
return ((int)r2->info - (int)r1->info);
}
static kmod_info_t * kmod_lookup(
kmod_info_t * kmods,
unsigned int kmod_count,
int kmod_id)
{
kmod_info_t * found_kmod = 0; unsigned int i;
for (i = 0; i < kmod_count; i++) {
kmod_info_t * this_kmod = &kmods[i];
if (this_kmod->id == kmod_id) {
found_kmod = this_kmod;
goto finish;
}
}
finish:
return found_kmod;
}
static void usage(int level)
{
fprintf(stderr, "usage: %s [-b kext_bundle_id] [-k] [-l]\n", progname);
return;
}