Index: usr.sbin/kldxref/kldxref.c =================================================================== --- usr.sbin/kldxref/kldxref.c +++ usr.sbin/kldxref/kldxref.c @@ -549,9 +549,9 @@ { struct mod_metadata md; struct elf_file ef; - void **p, **orgp; + void **p; int error, eftype; - long start, finish, entries; + long start, finish, entries, i; char cval[MAXMODNAME + 1]; if (verbose || dflag) @@ -575,18 +575,44 @@ &entries)); check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries, (void *)&p)); - orgp = p; - while(entries--) { - check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md), + /* + * Do a first pass to find MDT_MODULE. devmatch(8) requires it + * to be ordered first in the linker.hints stream. It appears + * some compilers or linkers reorder MODULE_METADATA entries + * from the source ordering, so we cannot rely on "just order + * DRIVER_MODULE before MODULE_PNP_INFO" to protect us. + * It's probably more ergonomic not to rely on that assumption + * anyways. + */ + for (i = 0; i < entries; i++) { + check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md), + &md)); + check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval, + sizeof(cval), cval)); + if (md.md_type == MDT_MODULE) { + parse_entry(&md, cval, &ef, kldname); + break; + } + } + if (error != 0) { + warnc(error, "error while reading %s", filename); + break; + } + + /* + * Second pass for all !MDT_MODULE entries. + */ + for (i = 0; i < entries; i++) { + check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md), &md)); - p++; check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); - parse_entry(&md, cval, &ef, kldname); + if (md.md_type != MDT_MODULE) + parse_entry(&md, cval, &ef, kldname); } if (error != 0) warnc(error, "error while reading %s", filename); - free(orgp); + free(p); } while(0); EF_CLOSE(&ef); return (error);