Hi,

On 9/25/26 3:13 AM, Ruslan Zalata wrote:
Hello All!

Playing with FreeBSD kernels, hacking driver code and debugging issues on laptops sometimes require knowledge of what KObjs are stored in kernel module file, their dependencies and, what's more important, for what version of kernel a particular module is built! Remember recent vboxdrv.ko version mismatch issue ?

Getting FreeBSD kernel module version info is a bit hacky. One of the ways involves using "nm" or "readelf" to get a list of special symbols, namely "_depend_on_" and "_version", then using "objdump" to get to .data section, then using "hexdump" to extract and fine-print version info. One also needs to write a script to glue these tools together, otherwise it's too easy make a mistake and get wrong data. After some time of struggling with this issue, I wrote mine in C, called "kldinfo". :-)

This as simple as a nail "kldinfo" utility behaves like "kldload", but instead of loading module it dumps list of objects it finds in module file along with their corresponding version and dependency info.

I propose to include "kldinfo" in FreeBSD base along with the other "kld*" utils. Note, a similar utility called "modinfo" has been present in most Linux distros for decades. I think we should have it in FreeBSD too. ;-) If that is ok, I will upload source code for review to Phabricator.

Repo: https://github.com/pointcheck/kldinfo.git

PS:

The code is fully written by hand, no LLMs have been involved.


This is very nice tool - thank You for writing it :)

I have played with it a little and introduced different formatting - proposal for new look below - along with the patch.

Regards,

vermaden




#./kldinfo /boot/kernel/kernel | head -30
MODULE: xpt                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: xpt                          DEPENDS: cam           VERSION:       1       1       1 MODULE: cam                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: aprobe                       DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: aprobe                       DEPENDS: cam           VERSION:       1       1       1 MODULE: pmp                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: pmp                          DEPENDS: cam           VERSION:       1       1       1 MODULE: nda                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: nda                          DEPENDS: cam           VERSION:       1       1       1 MODULE: nvme_probe                   DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: nvme_probe                   DEPENDS: cam           VERSION:       1       1       1 MODULE: probe                        DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: probe                        DEPENDS: cam           VERSION:       1       1       1 MODULE: cd                           DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: cd                           DEPENDS: cam           VERSION:       1       1       1 MODULE: ch                           DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: ch                           DEPENDS: cam           VERSION:       1       1       1 MODULE: ada                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: ada                          DEPENDS: cam           VERSION:       1       1       1 MODULE: da                           DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: da                           DEPENDS: cam           VERSION:       1       1       1 MODULE: pass                         DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: pass                         DEPENDS: cam           VERSION:       1       1       1 MODULE: sa                           DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: sa                           DEPENDS: cam           VERSION:       1       1       1 MODULE: enc                          DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: enc                          DEPENDS: cam           VERSION:       1       1       1 MODULE: xz                           DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: aacp_aac                     DEPENDS: kernel            VERSION: 1404000 1404000 1499999 MODULE: aacp                         DEPENDS: cam           VERSION:       1       1       1



# ./kldinfo -v /boot/kernel/acpi_ibm.ko
Section names are in section #19
Elf Section: name = .text, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x12288, type = 1
Elf Section: name = .rodata, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x4096, type = 1
Elf Section: name = .rela.text, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x9120, type = 13
Elf Section: name = .rela.rodata, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x2496, type = 13
Elf Section: name = .data, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x440, type = 1
Elf Section: name = .rela.data, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x672, type = 13
Elf Section: name = set_sysinit_set, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x16, type = 1
Elf Section: name = .relaset_sysinit_set, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x48, type = 13
Elf Section: name = set_sysuninit_set, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x8, type = 1
Elf Section: name = .relaset_sysuninit_set, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x24, type = 13
Elf Section: name = set_modmetadata_set, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x32, type = 1
Elf Section: name = .relaset_modmetadata_set, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x96, type = 13
Elf Section: name = .bss, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x32, type = 1
Elf Section: name = .comment, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x104, type = 1
Elf Section: name = .llvm_addrsig, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x57, type = 1
Elf Section: name = .note.gnu.build-id, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x36, type = 9
Elf Section: name = .note.GNU-stack, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x0, type = 1
Elf Section: name = .gnu_debuglink, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x24, type = 1
Elf Section: name = .shstrtab, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x294, type = 1
Elf Section: name = .SUNW_ctf, addr = 0x0, stab = #21
  Elf Data: off = 0x0, size = 0x3883, type = 1
Elf Section: name = .symtab, addr = 0x0, stab = #22
  Elf Data: off = 0x0, size = 0x3288, type = 18
  Symbol = ibm_ids, info = 0x01, sect = #5, size = 32, addr = 0x180
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = acpi_ibm_sysctls, info = 0x01, sect = #2, size = 480, addr = 0x270
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x1 (1)
  Symbol = ibm_sxlock, info = 0x01, sect = #13, size = 32, addr = 0x0
    No data buf for sec #13
  Symbol = ibm_sxlock_sx_sysinit_sys_init, info = 0x01, sect = #5, size = 32, addr = 0x18     ver1 = 0x1b00000 (28311552), ver2 = 0x1000000 (16777216), ver3 = 0x0 (0)
  Symbol = ibm_sxlock_args, info = 0x01, sect = #5, size = 24, addr = 0xd8
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = __set_sysinit_set_sym_ibm_sxlock_sx_sysinit_sys_init, info = 0x01, sect = #7, size = 8, addr = 0x0
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = ibm_sxlock_sx_sysuninit_sys_uninit, info = 0x01, sect = #5, size = 32, addr = 0x38     ver1 = 0x1b00000 (28311552), ver2 = 0x1000000 (16777216), ver3 = 0x0 (0)   Symbol = __set_sysuninit_set_sym_ibm_sxlock_sx_sysuninit_sys_uninit, info = 0x01, sect = #9, size = 8, addr = 0x0
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = _mod_metadata_md_acpi_ibm_acpi_on_kernel, info = 0x01, sect = #5, size = 24, addr = 0x58
    ver1 = 0x1 (1), ver2 = 0x1 (1), ver3 = 0x0 (0)
  Symbol = _acpi_ibm_acpi_depend_on_kernel, info = 0x01, sect = #5, size = 12, addr = 0xf0     ver1 = 0x156c60 (1404000), ver2 = 0x156c60 (1404000), ver3 = 0x156c60 (1404000)

MODULE: acpi_ibm_acpi                DEPENDS: kernel            VERSION: 1404000 1404000 1404000   Symbol = __set_modmetadata_set_sym__mod_metadata_md_acpi_ibm_acpi_on_kernel, info = 0x01, sect = #11, size = 8, addr = 0x0
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = _mod_metadata_md_acpi_ibm_acpi, info = 0x01, sect = #5, size = 24, addr = 0x70
    ver1 = 0x1 (1), ver2 = 0x2 (2), ver3 = 0x0 (0)
  Symbol = acpi_ibm_acpi_mod, info = 0x01, sect = #5, size = 24, addr = 0x100
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = __set_modmetadata_set_sym__mod_metadata_md_acpi_ibm_acpi, info = 0x01, sect = #11, size = 8, addr = 0x8
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = acpi_ibm_acpimodule_sys_init, info = 0x01, sect = #5, size = 32, addr = 0x88     ver1 = 0x3100000 (51380224), ver2 = 0x1000000 (16777216), ver3 = 0x0 (0)   Symbol = __set_sysinit_set_sym_acpi_ibm_acpimodule_sys_init, info = 0x01, sect = #7, size = 8, addr = 0x8
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = _mod_metadata_md_acpi_ibm_on_acpi, info = 0x01, sect = #5, size = 24, addr = 0xa8
    ver1 = 0x1 (1), ver2 = 0x1 (1), ver3 = 0x0 (0)
  Symbol = _acpi_ibm_depend_on_acpi, info = 0x01, sect = #5, size = 12, addr = 0x1a0
    ver1 = 0x1 (1), ver2 = 0x1 (1), ver3 = 0x1 (1)

MODULE: acpi_ibm                     DEPENDS: acpi            VERSION:       1       1       1   Symbol = __set_modmetadata_set_sym__mod_metadata_md_acpi_ibm_on_acpi, info = 0x01, sect = #11, size = 8, addr = 0x10
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = _mod_metadata_md_acpi_ibm_on_evdev, info = 0x01, sect = #5, size = 24, addr = 0xc0
    ver1 = 0x1 (1), ver2 = 0x1 (1), ver3 = 0x0 (0)
  Symbol = _acpi_ibm_depend_on_evdev, info = 0x01, sect = #5, size = 12, addr = 0x1ac
    ver1 = 0x1 (1), ver2 = 0x1 (1), ver3 = 0x1 (1)

MODULE: acpi_ibm                     DEPENDS: evdev           VERSION:       1       1       1   Symbol = __set_modmetadata_set_sym__mod_metadata_md_acpi_ibm_on_evdev, info = 0x01, sect = #11, size = 8, addr = 0x18
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x69706361 (1768973153)
  Symbol = acpi_ibm_acpi_driver_mod, info = 0x01, sect = #5, size = 48, addr = 0x118
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = acpi_ibm_driver, info = 0x01, sect = #5, size = 48, addr = 0x148
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = acpi_ibm_methods, info = 0x01, sect = #2, size = 80, addr = 0x220
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
  Symbol = acpi_ibm_models, info = 0x01, sect = #5, size = 24, addr = 0x0
    ver1 = 0x0 (0), ver2 = 0x0 (0), ver3 = 0x0 (0)
Elf Section: name = .strtab, addr = 0x0, stab = #0
  Elf Data: off = 0x0, size = 0x2485, type = 1

Found 3 dependencies in file /boot/kernel/acpi_ibm.ko



# diff -u kldinfo.c.OLD.geany kldinfo.c
--- kldinfo.c.OLD.geany 2026-09-25 13:55:55.352795000 +0200
+++ kldinfo.c   2026-09-25 13:54:02.349799000 +0200
@@ -67,7 +67,10 @@
   int dep_name_len = strlen(sym_name - mod_name_len -
     sizeof(DEPEND_ON));

-  printf("MODULE: %s\tDEPENDS: %s\tVERSION: %u %u %u\n",
+  if (verbose)
+    printf("\n");
+
+  printf("MODULE: %-28s DEPENDS: %-28s VERSION: %7u %7u %7u\n",
     mod_name, dep_name, ver1, ver2, ver3);

 }
@@ -86,7 +89,7 @@

   strncat(obj_name, sym_name, obj_name_len);

-  printf("OBJECT: %s\tVERSION: %u\n", obj_name, ver1);
+  printf("OBJECT: %-10s VERSION: %-10u\n", obj_name, ver1);
 }

 char *
@@ -246,7 +249,7 @@

     while ((elf_data = elf_getdata(elf_scn, elf_data))) {
       if (verbose)
-        printf("\tElf Data: off = 0x%lx, size = 0x%lu,"
+        printf("  Elf Data: off = 0x%lx, size = 0x%lu,"
           " type = %u\n",
           elf_data->d_off, elf_data->d_size,
           elf_data->d_type);
@@ -270,7 +273,7 @@
           elf_strptr(elf, stab, sym.st_name);

         if (verbose)
-          printf("\t\tSymbol = %s, info = 0x%02X,"
+          printf("  Symbol = %s, info = 0x%02X,"
             " sect = #%u, size = %lu,"
             " addr = 0x%lx\n",
             sym_name, sym.st_info, sym.st_shndx,
@@ -283,7 +286,7 @@

         if (scn == NULL) {
           if (verbose)
-            printf("\t\t"
+            printf("    "
               "Cannot get section #%u\n",
               sym.st_shndx);
           continue;
@@ -291,7 +294,7 @@

         if (gelf_getshdr(scn, &sh) == NULL) {
           if (verbose)
-            printf("\t\t"
+            printf("    "
               "Cannot get SH for #%u\n",
               sym.st_shndx);
           continue;
@@ -301,7 +304,7 @@

         if (data == NULL) {
           if (verbose)
-            printf("\t\t"
+            printf("    "
               "Cannot get data for #%u\n",
               sym.st_shndx);
           continue;
@@ -309,7 +312,7 @@

         if (data->d_buf == NULL) {
           if (verbose)
-            printf("\t\t"
+            printf("    "
               "No data buf for sec #%u\n",
               sym.st_shndx);
           continue;
@@ -328,7 +331,7 @@
           8 + sym.st_value - sh.sh_addr);

         if (verbose)
-          printf("\t\t"
+          printf("    "
             "ver1 = 0x%0x (%u), "
             "ver2 = 0x%0x (%u), "
             "ver3 = 0x%0x (%u)\n",
@@ -338,7 +341,7 @@
           uint8_t *c = (uint8_t *)data->d_buf +
             sym.st_value - sh.sh_addr;
           if (verbose) {
-            printf("\t\tFirmware list: ");
+            printf("    Firmware list: ");
             for (int i = 0;
                 i < sym.st_size; i++)
               printf("%02X ", c[i]);
@@ -364,6 +367,9 @@
   }

   elf_end(elf);
+
+  if (verbose)
+     printf("\n");

   if (deps_count)
     fprintf(stderr, "Found %u dependencies in file %s\n",

Reply via email to