19c6f9240SPeter Wemm /* 29c6f9240SPeter Wemm * Copyright (c) 2000, Boris Popov 39c6f9240SPeter Wemm * All rights reserved. 49c6f9240SPeter Wemm * 59c6f9240SPeter Wemm * Redistribution and use in source and binary forms, with or without 69c6f9240SPeter Wemm * modification, are permitted provided that the following conditions 79c6f9240SPeter Wemm * are met: 89c6f9240SPeter Wemm * 1. Redistributions of source code must retain the above copyright 99c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer. 109c6f9240SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 119c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer in the 129c6f9240SPeter Wemm * documentation and/or other materials provided with the distribution. 139c6f9240SPeter Wemm * 3. All advertising materials mentioning features or use of this software 149c6f9240SPeter Wemm * must display the following acknowledgement: 159c6f9240SPeter Wemm * This product includes software developed by Boris Popov. 169c6f9240SPeter Wemm * 4. Neither the name of the author nor the names of any co-contributors 179c6f9240SPeter Wemm * may be used to endorse or promote products derived from this software 189c6f9240SPeter Wemm * without specific prior written permission. 199c6f9240SPeter Wemm * 209c6f9240SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 219c6f9240SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 229c6f9240SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239c6f9240SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 249c6f9240SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 259c6f9240SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 269c6f9240SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 279c6f9240SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289c6f9240SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 299c6f9240SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 309c6f9240SPeter Wemm * SUCH DAMAGE. 319c6f9240SPeter Wemm * 329c6f9240SPeter Wemm * $FreeBSD$ 339c6f9240SPeter Wemm */ 349c6f9240SPeter Wemm 359c6f9240SPeter Wemm #include <sys/param.h> 369c6f9240SPeter Wemm #include <sys/exec.h> 379c6f9240SPeter Wemm #include <sys/queue.h> 389c6f9240SPeter Wemm #include <sys/kernel.h> 399c6f9240SPeter Wemm #include <sys/reboot.h> 409c6f9240SPeter Wemm #include <sys/linker.h> 419c6f9240SPeter Wemm #include <sys/stat.h> 429c6f9240SPeter Wemm #include <sys/module.h> 439c6f9240SPeter Wemm #define FREEBSD_ELF 449c6f9240SPeter Wemm #include <link.h> 459c6f9240SPeter Wemm #include <err.h> 469c6f9240SPeter Wemm #include <fts.h> 479c6f9240SPeter Wemm #include <string.h> 489c6f9240SPeter Wemm #include <machine/elf.h> 499c6f9240SPeter Wemm #include <stdio.h> 509c6f9240SPeter Wemm #include <stdlib.h> 519c6f9240SPeter Wemm #include <unistd.h> 529c6f9240SPeter Wemm #include <errno.h> 539c6f9240SPeter Wemm 549c6f9240SPeter Wemm #include "ef.h" 559c6f9240SPeter Wemm 569c6f9240SPeter Wemm #define MAXRECSIZE 1024 579c6f9240SPeter Wemm #define check(val) if ((error = (val)) != 0) break 589c6f9240SPeter Wemm 599c6f9240SPeter Wemm #ifndef min 609c6f9240SPeter Wemm #define min(a,b) (((a)<(b)) ? (a) : (b)) 619c6f9240SPeter Wemm #endif 629c6f9240SPeter Wemm 639c6f9240SPeter Wemm struct mod_info { 649c6f9240SPeter Wemm char* mi_name; 659c6f9240SPeter Wemm int mi_ver; 669c6f9240SPeter Wemm SLIST_ENTRY(mod_info) mi_next; 679c6f9240SPeter Wemm }; 689c6f9240SPeter Wemm 699c6f9240SPeter Wemm #ifdef notnow 709c6f9240SPeter Wemm struct kld_info { 719c6f9240SPeter Wemm char* k_filename; 729c6f9240SPeter Wemm SLIST_HEAD(mod_list_head, mod_info) k_modules; 739c6f9240SPeter Wemm SLIST_ENTRY(kld_info) k_next; 749c6f9240SPeter Wemm }; 759c6f9240SPeter Wemm 769c6f9240SPeter Wemm SLIST_HEAD(kld_list_head, kld_info) kldlist; 779c6f9240SPeter Wemm #endif 789c6f9240SPeter Wemm 799c6f9240SPeter Wemm static int dflag, verbose; 809c6f9240SPeter Wemm 819c6f9240SPeter Wemm FILE *fxref; 829c6f9240SPeter Wemm 8387e5cd7cSMike Heffner static const char *xref_file = "linker.hints"; 849c6f9240SPeter Wemm 859c6f9240SPeter Wemm static char recbuf[MAXRECSIZE]; 869c6f9240SPeter Wemm static int recpos, reccnt; 879c6f9240SPeter Wemm 8887e5cd7cSMike Heffner void maketempfile(char *, const char *); 899c6f9240SPeter Wemm static void usage(void); 909c6f9240SPeter Wemm 919c6f9240SPeter Wemm static void 929c6f9240SPeter Wemm intalign(void) 939c6f9240SPeter Wemm { 949c6f9240SPeter Wemm recpos = (recpos + sizeof(int) - 1) & ~(sizeof(int) - 1); 959c6f9240SPeter Wemm } 969c6f9240SPeter Wemm 979c6f9240SPeter Wemm static void 989c6f9240SPeter Wemm record_start(void) 999c6f9240SPeter Wemm { 1009c6f9240SPeter Wemm recpos = 0; 1019c6f9240SPeter Wemm memset(recbuf, 0, MAXRECSIZE); 1029c6f9240SPeter Wemm } 1039c6f9240SPeter Wemm 1049c6f9240SPeter Wemm static int 1059c6f9240SPeter Wemm record_end(void) 1069c6f9240SPeter Wemm { 1079c6f9240SPeter Wemm if (dflag || recpos == 0) 1089c6f9240SPeter Wemm return 0; 1099c6f9240SPeter Wemm reccnt++; 1109c6f9240SPeter Wemm intalign(); 1119c6f9240SPeter Wemm fwrite(&recpos, sizeof(recpos), 1, fxref); 1129c6f9240SPeter Wemm return fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0; 1139c6f9240SPeter Wemm } 1149c6f9240SPeter Wemm 1159c6f9240SPeter Wemm static int 1169c6f9240SPeter Wemm record_buf(const void *buf, int size) 1179c6f9240SPeter Wemm { 1189c6f9240SPeter Wemm if (MAXRECSIZE - recpos < size) 1199c6f9240SPeter Wemm errx(1, "record buffer overflow"); 1209c6f9240SPeter Wemm memcpy(recbuf + recpos, buf, size); 1219c6f9240SPeter Wemm recpos += size; 1229c6f9240SPeter Wemm return 0; 1239c6f9240SPeter Wemm } 1249c6f9240SPeter Wemm 1259c6f9240SPeter Wemm static int 1269c6f9240SPeter Wemm record_int(int val) 1279c6f9240SPeter Wemm { 1289c6f9240SPeter Wemm intalign(); 1299c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 1309c6f9240SPeter Wemm } 1319c6f9240SPeter Wemm 1329c6f9240SPeter Wemm static int 1339c6f9240SPeter Wemm record_byte(u_char val) 1349c6f9240SPeter Wemm { 1359c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 1369c6f9240SPeter Wemm } 1379c6f9240SPeter Wemm 1389c6f9240SPeter Wemm static int 1399c6f9240SPeter Wemm record_string(const char *str) 1409c6f9240SPeter Wemm { 1419c6f9240SPeter Wemm int len = strlen(str); 1429c6f9240SPeter Wemm int error; 1439c6f9240SPeter Wemm 1449c6f9240SPeter Wemm if (dflag) 1459c6f9240SPeter Wemm return 0; 1469c6f9240SPeter Wemm error = record_byte(len); 1479c6f9240SPeter Wemm if (error) 1489c6f9240SPeter Wemm return error; 1499c6f9240SPeter Wemm return record_buf(str, len); 1509c6f9240SPeter Wemm } 1519c6f9240SPeter Wemm 1529c6f9240SPeter Wemm static int 1539c6f9240SPeter Wemm parse_entry(struct mod_metadata *md, const char *cval, 1549c6f9240SPeter Wemm struct elf_file *ef, const char *kldname) 1559c6f9240SPeter Wemm { 1569c6f9240SPeter Wemm struct mod_depend mdp; 1579c6f9240SPeter Wemm struct mod_version mdv; 1589c6f9240SPeter Wemm Elf_Off data = (Elf_Off)md->md_data; 1599c6f9240SPeter Wemm int error = 0; 1609c6f9240SPeter Wemm 1619c6f9240SPeter Wemm record_start(); 1629c6f9240SPeter Wemm switch (md->md_type) { 1639c6f9240SPeter Wemm case MDT_DEPEND: 1649c6f9240SPeter Wemm if (!dflag) 1659c6f9240SPeter Wemm break; 1669c6f9240SPeter Wemm check(ef_seg_read(ef, data, sizeof(mdp), (void**)&mdp)); 1679c6f9240SPeter Wemm printf(" depends on %s.%d (%d,%d)\n", cval, 1689c6f9240SPeter Wemm mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum); 1699c6f9240SPeter Wemm break; 1709c6f9240SPeter Wemm case MDT_VERSION: 1719c6f9240SPeter Wemm check(ef_seg_read(ef, data, sizeof(mdv), (void**)&mdv)); 1729c6f9240SPeter Wemm record_int(MDT_VERSION); 1739c6f9240SPeter Wemm record_string(cval); 1749c6f9240SPeter Wemm record_int(mdv.mv_version); 1759c6f9240SPeter Wemm record_string(kldname); 1769c6f9240SPeter Wemm if (!dflag) 1779c6f9240SPeter Wemm break; 1789c6f9240SPeter Wemm printf(" interface %s.%d\n", cval, mdv.mv_version); 1799c6f9240SPeter Wemm break; 1809c6f9240SPeter Wemm case MDT_MODULE: 1819c6f9240SPeter Wemm record_int(MDT_MODULE); 1829c6f9240SPeter Wemm record_string(cval); 1839c6f9240SPeter Wemm record_string(kldname); 1849c6f9240SPeter Wemm if (!dflag) 1859c6f9240SPeter Wemm break; 1869c6f9240SPeter Wemm printf(" module %s\n", cval); 1879c6f9240SPeter Wemm break; 1889c6f9240SPeter Wemm default: 1899c6f9240SPeter Wemm warnx("unknown metdata record %d in file %s", md->md_type, kldname); 1909c6f9240SPeter Wemm } 1919c6f9240SPeter Wemm if (!error) 1929c6f9240SPeter Wemm record_end(); 1939c6f9240SPeter Wemm return error; 1949c6f9240SPeter Wemm } 1959c6f9240SPeter Wemm 1969c6f9240SPeter Wemm static int 1979c6f9240SPeter Wemm read_kld(char *filename, char *kldname) 1989c6f9240SPeter Wemm { 1999c6f9240SPeter Wemm struct mod_metadata md; 2009c6f9240SPeter Wemm struct elf_file ef; 2019c6f9240SPeter Wemm /* struct kld_info *kip; 2029c6f9240SPeter Wemm struct mod_info *mip;*/ 2039c6f9240SPeter Wemm void **p, **orgp; 2049c6f9240SPeter Wemm int error, nmlen; 2059c6f9240SPeter Wemm long start, finish, entries; 2069c6f9240SPeter Wemm Elf_Sym *sym; 2079c6f9240SPeter Wemm char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp; 2089c6f9240SPeter Wemm 2099c6f9240SPeter Wemm if (verbose || dflag) 2109c6f9240SPeter Wemm printf("%s\n", filename); 2119c6f9240SPeter Wemm error = ef_open(filename, &ef, verbose); 2129c6f9240SPeter Wemm if (error) 2139c6f9240SPeter Wemm return error; 2149c6f9240SPeter Wemm if (ef.ef_type != EFT_KLD && ef.ef_type != EFT_KERNEL) { 2159c6f9240SPeter Wemm ef_close(&ef); 2169c6f9240SPeter Wemm return 0; 2179c6f9240SPeter Wemm } 2189c6f9240SPeter Wemm if (!dflag) { 2199c6f9240SPeter Wemm cp = strrchr(kldname, '.'); 2209c6f9240SPeter Wemm nmlen = cp ? min(MAXMODNAME, cp - kldname) : 2219c6f9240SPeter Wemm min(MAXMODNAME, strlen(kldname)); 2229c6f9240SPeter Wemm strncpy(kldmodname, kldname, nmlen); 2239c6f9240SPeter Wemm kldmodname[nmlen] = '\0'; 2249c6f9240SPeter Wemm /* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/ 2259c6f9240SPeter Wemm } 2269c6f9240SPeter Wemm do { 2279c6f9240SPeter Wemm check(ef_lookup_symbol(&ef, "__start_set_" MDT_SETNAME, &sym)); 2289c6f9240SPeter Wemm start = sym->st_value; 2299c6f9240SPeter Wemm check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym)); 2309c6f9240SPeter Wemm finish = sym->st_value; 2319c6f9240SPeter Wemm entries = (finish - start) / sizeof(void *); 2329c6f9240SPeter Wemm check(ef_seg_read_entry(&ef, start, sizeof(*p) * entries, (void**)&p)); 2339c6f9240SPeter Wemm orgp = p; 2349c6f9240SPeter Wemm while(entries--) { 2359c6f9240SPeter Wemm check(ef_seg_read(&ef, (Elf_Off)*p, sizeof(md), &md)); 2369c6f9240SPeter Wemm p++; 2379c6f9240SPeter Wemm check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); 2389c6f9240SPeter Wemm cval[MAXMODNAME] = '\0'; 2399c6f9240SPeter Wemm parse_entry(&md, cval, &ef, kldname); 2409c6f9240SPeter Wemm } 2419c6f9240SPeter Wemm if (error) 2429c6f9240SPeter Wemm warnc(error, "error while reading %s", filename); 2439c6f9240SPeter Wemm free(orgp); 2449c6f9240SPeter Wemm } while(0); 2459c6f9240SPeter Wemm ef_close(&ef); 2469c6f9240SPeter Wemm return error; 2479c6f9240SPeter Wemm } 2489c6f9240SPeter Wemm 2499c6f9240SPeter Wemm void 2509c6f9240SPeter Wemm maketempfile(char *dest, const char *root) 2519c6f9240SPeter Wemm { 2529c6f9240SPeter Wemm char *p; 2539c6f9240SPeter Wemm 2549c6f9240SPeter Wemm strncpy(dest, root, MAXPATHLEN - 1); 2559c6f9240SPeter Wemm dest[MAXPATHLEN] = '\0'; 2569c6f9240SPeter Wemm 2579c6f9240SPeter Wemm if ((p = strrchr(dest, '/')) != 0) 2589c6f9240SPeter Wemm p++; 2599c6f9240SPeter Wemm else 2609c6f9240SPeter Wemm p = dest; 2619c6f9240SPeter Wemm strcpy(p, "lhint.XXXXXX"); 2629c6f9240SPeter Wemm if (mkstemp(dest) == -1) 2639c6f9240SPeter Wemm err(1, "%s", dest); 2649c6f9240SPeter Wemm } 2659c6f9240SPeter Wemm 2669c6f9240SPeter Wemm static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; 2679c6f9240SPeter Wemm 2689c6f9240SPeter Wemm int 2699c6f9240SPeter Wemm main(int argc, char *argv[]) 2709c6f9240SPeter Wemm { 2719c6f9240SPeter Wemm FTS *ftsp; 2729c6f9240SPeter Wemm FTSENT *p; 2739c6f9240SPeter Wemm int opt, fts_options, ival; 2749c6f9240SPeter Wemm 2759c6f9240SPeter Wemm fts_options = FTS_PHYSICAL; 2769c6f9240SPeter Wemm /* SLIST_INIT(&kldlist);*/ 2779c6f9240SPeter Wemm 2789c6f9240SPeter Wemm while ((opt = getopt(argc, argv, "Rdf:v")) != -1) { 2799c6f9240SPeter Wemm switch (opt) { 2809c6f9240SPeter Wemm case 'd': 2819c6f9240SPeter Wemm dflag = 1; 2829c6f9240SPeter Wemm break; 2839c6f9240SPeter Wemm case 'f': 2849c6f9240SPeter Wemm xref_file = optarg; 2859c6f9240SPeter Wemm break; 2869c6f9240SPeter Wemm case 'v': 2879c6f9240SPeter Wemm verbose++; 2889c6f9240SPeter Wemm break; 2899c6f9240SPeter Wemm case 'R': 2909c6f9240SPeter Wemm fts_options |= FTS_COMFOLLOW; 2919c6f9240SPeter Wemm break; 2929c6f9240SPeter Wemm default: 2939c6f9240SPeter Wemm usage(); 2949c6f9240SPeter Wemm /* NOTREACHED */ 2959c6f9240SPeter Wemm } 2969c6f9240SPeter Wemm } 2979c6f9240SPeter Wemm if (argc - optind < 1) 2989c6f9240SPeter Wemm usage(); 2999c6f9240SPeter Wemm argc -= optind; 3009c6f9240SPeter Wemm argv += optind; 3019c6f9240SPeter Wemm 3029c6f9240SPeter Wemm ftsp = fts_open(argv, fts_options, 0); 3039c6f9240SPeter Wemm if (ftsp == NULL) 3049c6f9240SPeter Wemm exit(1); 3059c6f9240SPeter Wemm 3069c6f9240SPeter Wemm for (;;) { 3079c6f9240SPeter Wemm p = fts_read(ftsp); 3089c6f9240SPeter Wemm if ((p == NULL || p->fts_info == FTS_D) && !dflag && fxref) { 3099c6f9240SPeter Wemm fclose(fxref); 3109c6f9240SPeter Wemm if (reccnt) { 3119c6f9240SPeter Wemm rename(tempname, xrefname); 3129c6f9240SPeter Wemm } else { 3139c6f9240SPeter Wemm unlink(tempname); 3149c6f9240SPeter Wemm unlink(xrefname); 3159c6f9240SPeter Wemm } 3169c6f9240SPeter Wemm } 3179c6f9240SPeter Wemm if (p == NULL) 3189c6f9240SPeter Wemm break; 3199c6f9240SPeter Wemm if (p && p->fts_info == FTS_D && !dflag) { 3209c6f9240SPeter Wemm snprintf(xrefname, sizeof(xrefname), "%s/%s", 3219c6f9240SPeter Wemm ftsp->fts_path, xref_file); 3229c6f9240SPeter Wemm maketempfile(tempname, ftsp->fts_path); 3239c6f9240SPeter Wemm fxref = fopen(tempname, "w+t"); 3249c6f9240SPeter Wemm if (fxref == NULL) 3259c6f9240SPeter Wemm err(1, "can't create %s", tempname); 3269c6f9240SPeter Wemm ival = 1; 3279c6f9240SPeter Wemm fwrite(&ival, sizeof(ival), 1, fxref); 3289c6f9240SPeter Wemm reccnt = 0; 3299c6f9240SPeter Wemm } 3309c6f9240SPeter Wemm if (p->fts_info != FTS_F) 3319c6f9240SPeter Wemm continue; 3329c6f9240SPeter Wemm read_kld(p->fts_path, p->fts_name); 3339c6f9240SPeter Wemm } 3349c6f9240SPeter Wemm fts_close(ftsp); 3359c6f9240SPeter Wemm return 0; 3369c6f9240SPeter Wemm } 3379c6f9240SPeter Wemm 3389c6f9240SPeter Wemm static void 3399c6f9240SPeter Wemm usage(void) 3409c6f9240SPeter Wemm { 3419c6f9240SPeter Wemm 3429c6f9240SPeter Wemm fprintf(stderr, "%s\n", 343*d3974088SDag-Erling Smørgrav "usage: kldxref [-Rdv] [-f hintfile] path [path..]" 3449c6f9240SPeter Wemm ); 3459c6f9240SPeter Wemm exit(1); 3469c6f9240SPeter Wemm } 347