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 35b7abc67eSMaxim Sobolev #include <sys/types.h> 369c6f9240SPeter Wemm #include <sys/param.h> 379c6f9240SPeter Wemm #include <sys/exec.h> 389c6f9240SPeter Wemm #include <sys/queue.h> 399c6f9240SPeter Wemm #include <sys/kernel.h> 409c6f9240SPeter Wemm #include <sys/reboot.h> 419c6f9240SPeter Wemm #include <sys/linker.h> 429c6f9240SPeter Wemm #include <sys/stat.h> 439c6f9240SPeter Wemm #include <sys/module.h> 449c6f9240SPeter Wemm #define FREEBSD_ELF 459c6f9240SPeter Wemm #include <link.h> 469c6f9240SPeter Wemm #include <err.h> 479c6f9240SPeter Wemm #include <fts.h> 489c6f9240SPeter Wemm #include <string.h> 499c6f9240SPeter Wemm #include <machine/elf.h> 509c6f9240SPeter Wemm #include <stdio.h> 519c6f9240SPeter Wemm #include <stdlib.h> 529c6f9240SPeter Wemm #include <unistd.h> 539c6f9240SPeter Wemm #include <errno.h> 549c6f9240SPeter Wemm 559c6f9240SPeter Wemm #include "ef.h" 569c6f9240SPeter Wemm 579c6f9240SPeter Wemm #define MAXRECSIZE 1024 589c6f9240SPeter Wemm #define check(val) if ((error = (val)) != 0) break 599c6f9240SPeter Wemm 609c6f9240SPeter Wemm #ifndef min 619c6f9240SPeter Wemm #define min(a,b) (((a)<(b)) ? (a) : (b)) 629c6f9240SPeter Wemm #endif 639c6f9240SPeter Wemm 649c6f9240SPeter Wemm struct mod_info { 659c6f9240SPeter Wemm char* mi_name; 669c6f9240SPeter Wemm int mi_ver; 679c6f9240SPeter Wemm SLIST_ENTRY(mod_info) mi_next; 689c6f9240SPeter Wemm }; 699c6f9240SPeter Wemm 709c6f9240SPeter Wemm #ifdef notnow 719c6f9240SPeter Wemm struct kld_info { 729c6f9240SPeter Wemm char* k_filename; 739c6f9240SPeter Wemm SLIST_HEAD(mod_list_head, mod_info) k_modules; 749c6f9240SPeter Wemm SLIST_ENTRY(kld_info) k_next; 759c6f9240SPeter Wemm }; 769c6f9240SPeter Wemm 779c6f9240SPeter Wemm SLIST_HEAD(kld_list_head, kld_info) kldlist; 789c6f9240SPeter Wemm #endif 799c6f9240SPeter Wemm 809c6f9240SPeter Wemm static int dflag, verbose; 819c6f9240SPeter Wemm 829c6f9240SPeter Wemm FILE *fxref; 839c6f9240SPeter Wemm 8487e5cd7cSMike Heffner static const char *xref_file = "linker.hints"; 859c6f9240SPeter Wemm 869c6f9240SPeter Wemm static char recbuf[MAXRECSIZE]; 879c6f9240SPeter Wemm static int recpos, reccnt; 889c6f9240SPeter Wemm 899ceddbd5SMarcel Moolenaar FILE *maketempfile(char *, const char *); 909c6f9240SPeter Wemm static void usage(void); 919c6f9240SPeter Wemm 929c6f9240SPeter Wemm static void 939c6f9240SPeter Wemm intalign(void) 949c6f9240SPeter Wemm { 959c6f9240SPeter Wemm recpos = (recpos + sizeof(int) - 1) & ~(sizeof(int) - 1); 969c6f9240SPeter Wemm } 979c6f9240SPeter Wemm 989c6f9240SPeter Wemm static void 999c6f9240SPeter Wemm record_start(void) 1009c6f9240SPeter Wemm { 1019c6f9240SPeter Wemm recpos = 0; 1029c6f9240SPeter Wemm memset(recbuf, 0, MAXRECSIZE); 1039c6f9240SPeter Wemm } 1049c6f9240SPeter Wemm 1059c6f9240SPeter Wemm static int 1069c6f9240SPeter Wemm record_end(void) 1079c6f9240SPeter Wemm { 1089c6f9240SPeter Wemm if (dflag || recpos == 0) 1099c6f9240SPeter Wemm return 0; 1109c6f9240SPeter Wemm reccnt++; 1119c6f9240SPeter Wemm intalign(); 1129c6f9240SPeter Wemm fwrite(&recpos, sizeof(recpos), 1, fxref); 1139c6f9240SPeter Wemm return fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0; 1149c6f9240SPeter Wemm } 1159c6f9240SPeter Wemm 1169c6f9240SPeter Wemm static int 1179c6f9240SPeter Wemm record_buf(const void *buf, int size) 1189c6f9240SPeter Wemm { 1199c6f9240SPeter Wemm if (MAXRECSIZE - recpos < size) 1209c6f9240SPeter Wemm errx(1, "record buffer overflow"); 1219c6f9240SPeter Wemm memcpy(recbuf + recpos, buf, size); 1229c6f9240SPeter Wemm recpos += size; 1239c6f9240SPeter Wemm return 0; 1249c6f9240SPeter Wemm } 1259c6f9240SPeter Wemm 1269c6f9240SPeter Wemm static int 1279c6f9240SPeter Wemm record_int(int val) 1289c6f9240SPeter Wemm { 1299c6f9240SPeter Wemm intalign(); 1309c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 1319c6f9240SPeter Wemm } 1329c6f9240SPeter Wemm 1339c6f9240SPeter Wemm static int 1349c6f9240SPeter Wemm record_byte(u_char val) 1359c6f9240SPeter Wemm { 1369c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 1379c6f9240SPeter Wemm } 1389c6f9240SPeter Wemm 1399c6f9240SPeter Wemm static int 1409c6f9240SPeter Wemm record_string(const char *str) 1419c6f9240SPeter Wemm { 1429c6f9240SPeter Wemm int len = strlen(str); 1439c6f9240SPeter Wemm int error; 1449c6f9240SPeter Wemm 1459c6f9240SPeter Wemm if (dflag) 1469c6f9240SPeter Wemm return 0; 1479c6f9240SPeter Wemm error = record_byte(len); 1489c6f9240SPeter Wemm if (error) 1499c6f9240SPeter Wemm return error; 1509c6f9240SPeter Wemm return record_buf(str, len); 1519c6f9240SPeter Wemm } 1529c6f9240SPeter Wemm 1539c6f9240SPeter Wemm static int 1549c6f9240SPeter Wemm parse_entry(struct mod_metadata *md, const char *cval, 1559c6f9240SPeter Wemm struct elf_file *ef, const char *kldname) 1569c6f9240SPeter Wemm { 1579c6f9240SPeter Wemm struct mod_depend mdp; 1589c6f9240SPeter Wemm struct mod_version mdv; 1599c6f9240SPeter Wemm Elf_Off data = (Elf_Off)md->md_data; 1609c6f9240SPeter Wemm int error = 0; 1619c6f9240SPeter Wemm 1629c6f9240SPeter Wemm record_start(); 1639c6f9240SPeter Wemm switch (md->md_type) { 1649c6f9240SPeter Wemm case MDT_DEPEND: 1659c6f9240SPeter Wemm if (!dflag) 1669c6f9240SPeter Wemm break; 1679772dc2aSIan Dowse check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp)); 1689c6f9240SPeter Wemm printf(" depends on %s.%d (%d,%d)\n", cval, 1699c6f9240SPeter Wemm mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum); 1709c6f9240SPeter Wemm break; 1719c6f9240SPeter Wemm case MDT_VERSION: 1729772dc2aSIan Dowse check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv)); 1739c6f9240SPeter Wemm record_int(MDT_VERSION); 1749c6f9240SPeter Wemm record_string(cval); 1759c6f9240SPeter Wemm record_int(mdv.mv_version); 1769c6f9240SPeter Wemm record_string(kldname); 1779c6f9240SPeter Wemm if (!dflag) 1789c6f9240SPeter Wemm break; 1799c6f9240SPeter Wemm printf(" interface %s.%d\n", cval, mdv.mv_version); 1809c6f9240SPeter Wemm break; 1819c6f9240SPeter Wemm case MDT_MODULE: 1829c6f9240SPeter Wemm record_int(MDT_MODULE); 1839c6f9240SPeter Wemm record_string(cval); 1849c6f9240SPeter Wemm record_string(kldname); 1859c6f9240SPeter Wemm if (!dflag) 1869c6f9240SPeter Wemm break; 1879c6f9240SPeter Wemm printf(" module %s\n", cval); 1889c6f9240SPeter Wemm break; 1899c6f9240SPeter Wemm default: 1909f5529b4SRuslan Ermilov warnx("unknown metadata record %d in file %s", md->md_type, kldname); 1919c6f9240SPeter Wemm } 1929c6f9240SPeter Wemm if (!error) 1939c6f9240SPeter Wemm record_end(); 1949c6f9240SPeter Wemm return error; 1959c6f9240SPeter Wemm } 1969c6f9240SPeter Wemm 1979c6f9240SPeter Wemm static int 1989c6f9240SPeter Wemm read_kld(char *filename, char *kldname) 1999c6f9240SPeter Wemm { 2009c6f9240SPeter Wemm struct mod_metadata md; 2019c6f9240SPeter Wemm struct elf_file ef; 2029c6f9240SPeter Wemm /* struct kld_info *kip; 2039c6f9240SPeter Wemm struct mod_info *mip;*/ 2049c6f9240SPeter Wemm void **p, **orgp; 2059772dc2aSIan Dowse int error, eftype, nmlen; 2069c6f9240SPeter Wemm long start, finish, entries; 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); 2129772dc2aSIan Dowse if (error) { 2134a8b7e33SIan Dowse error = ef_obj_open(filename, &ef, verbose); 2144a8b7e33SIan Dowse if (error) { 2159772dc2aSIan Dowse if (verbose) 2169772dc2aSIan Dowse warnc(error, "elf_open(%s)", filename); 2179c6f9240SPeter Wemm return error; 2189772dc2aSIan Dowse } 2194a8b7e33SIan Dowse } 2209772dc2aSIan Dowse eftype = EF_GET_TYPE(&ef); 2219772dc2aSIan Dowse if (eftype != EFT_KLD && eftype != EFT_KERNEL) { 2229772dc2aSIan Dowse EF_CLOSE(&ef); 2239c6f9240SPeter Wemm return 0; 2249c6f9240SPeter Wemm } 2259c6f9240SPeter Wemm if (!dflag) { 2269c6f9240SPeter Wemm cp = strrchr(kldname, '.'); 2279c6f9240SPeter Wemm nmlen = cp ? min(MAXMODNAME, cp - kldname) : 2289c6f9240SPeter Wemm min(MAXMODNAME, strlen(kldname)); 229*2fdfd0feSWarner Losh strlcpy(kldmodname, kldname, nmlen); 2309c6f9240SPeter Wemm /* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/ 2319c6f9240SPeter Wemm } 2329c6f9240SPeter Wemm do { 2339772dc2aSIan Dowse check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish, 2349772dc2aSIan Dowse &entries)); 2359772dc2aSIan Dowse check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries, 23676798703SDag-Erling Smørgrav (void *)&p)); 2379c6f9240SPeter Wemm orgp = p; 2389c6f9240SPeter Wemm while(entries--) { 2399772dc2aSIan Dowse check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md), 2409772dc2aSIan Dowse &md)); 2419c6f9240SPeter Wemm p++; 2429772dc2aSIan Dowse check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval, 2439772dc2aSIan Dowse sizeof(cval), cval)); 2449c6f9240SPeter Wemm cval[MAXMODNAME] = '\0'; 2459c6f9240SPeter Wemm parse_entry(&md, cval, &ef, kldname); 2469c6f9240SPeter Wemm } 2479c6f9240SPeter Wemm if (error) 2489c6f9240SPeter Wemm warnc(error, "error while reading %s", filename); 2499c6f9240SPeter Wemm free(orgp); 2509c6f9240SPeter Wemm } while(0); 2519772dc2aSIan Dowse EF_CLOSE(&ef); 2529c6f9240SPeter Wemm return error; 2539c6f9240SPeter Wemm } 2549c6f9240SPeter Wemm 2559ceddbd5SMarcel Moolenaar FILE * 2569c6f9240SPeter Wemm maketempfile(char *dest, const char *root) 2579c6f9240SPeter Wemm { 2589c6f9240SPeter Wemm char *p; 2599ceddbd5SMarcel Moolenaar int fd; 2609c6f9240SPeter Wemm 261*2fdfd0feSWarner Losh strlcpy(dest, root, MAXPATHLEN); 2629c6f9240SPeter Wemm 2639c6f9240SPeter Wemm if ((p = strrchr(dest, '/')) != 0) 2649c6f9240SPeter Wemm p++; 2659c6f9240SPeter Wemm else 2669c6f9240SPeter Wemm p = dest; 2679c6f9240SPeter Wemm strcpy(p, "lhint.XXXXXX"); 2689ceddbd5SMarcel Moolenaar fd = mkstemp(dest); 2699ceddbd5SMarcel Moolenaar return ((fd == -1) ? NULL : fdopen(fd, "w+")); 2709c6f9240SPeter Wemm } 2719c6f9240SPeter Wemm 2729c6f9240SPeter Wemm static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; 2739c6f9240SPeter Wemm 2749c6f9240SPeter Wemm int 2759c6f9240SPeter Wemm main(int argc, char *argv[]) 2769c6f9240SPeter Wemm { 2779c6f9240SPeter Wemm FTS *ftsp; 2789c6f9240SPeter Wemm FTSENT *p; 2799c6f9240SPeter Wemm int opt, fts_options, ival; 280b7abc67eSMaxim Sobolev struct stat sb; 2819c6f9240SPeter Wemm 2829c6f9240SPeter Wemm fts_options = FTS_PHYSICAL; 2839c6f9240SPeter Wemm /* SLIST_INIT(&kldlist);*/ 2849c6f9240SPeter Wemm 2859c6f9240SPeter Wemm while ((opt = getopt(argc, argv, "Rdf:v")) != -1) { 2869c6f9240SPeter Wemm switch (opt) { 2879c6f9240SPeter Wemm case 'd': 2889c6f9240SPeter Wemm dflag = 1; 2899c6f9240SPeter Wemm break; 2909c6f9240SPeter Wemm case 'f': 2919c6f9240SPeter Wemm xref_file = optarg; 2929c6f9240SPeter Wemm break; 2939c6f9240SPeter Wemm case 'v': 2949c6f9240SPeter Wemm verbose++; 2959c6f9240SPeter Wemm break; 2969c6f9240SPeter Wemm case 'R': 2979c6f9240SPeter Wemm fts_options |= FTS_COMFOLLOW; 2989c6f9240SPeter Wemm break; 2999c6f9240SPeter Wemm default: 3009c6f9240SPeter Wemm usage(); 3019c6f9240SPeter Wemm /* NOTREACHED */ 3029c6f9240SPeter Wemm } 3039c6f9240SPeter Wemm } 3049c6f9240SPeter Wemm if (argc - optind < 1) 3059c6f9240SPeter Wemm usage(); 3069c6f9240SPeter Wemm argc -= optind; 3079c6f9240SPeter Wemm argv += optind; 3089c6f9240SPeter Wemm 309b7abc67eSMaxim Sobolev if (stat(argv[0], &sb) != 0) 310b7abc67eSMaxim Sobolev err(1, "%s", argv[0]); 311b7abc67eSMaxim Sobolev if ((sb.st_mode & S_IFDIR) == 0) { 312b7abc67eSMaxim Sobolev errno = ENOTDIR; 313b7abc67eSMaxim Sobolev err(1, "%s", argv[0]); 314b7abc67eSMaxim Sobolev } 315b7abc67eSMaxim Sobolev 3169c6f9240SPeter Wemm ftsp = fts_open(argv, fts_options, 0); 3179c6f9240SPeter Wemm if (ftsp == NULL) 3189c6f9240SPeter Wemm exit(1); 3199c6f9240SPeter Wemm 3209c6f9240SPeter Wemm for (;;) { 3219c6f9240SPeter Wemm p = fts_read(ftsp); 3229c6f9240SPeter Wemm if ((p == NULL || p->fts_info == FTS_D) && !dflag && fxref) { 3239c6f9240SPeter Wemm fclose(fxref); 3249ceddbd5SMarcel Moolenaar fxref = NULL; 3259c6f9240SPeter Wemm if (reccnt) { 3269c6f9240SPeter Wemm rename(tempname, xrefname); 3279c6f9240SPeter Wemm } else { 3289c6f9240SPeter Wemm unlink(tempname); 3299c6f9240SPeter Wemm unlink(xrefname); 3309c6f9240SPeter Wemm } 3319c6f9240SPeter Wemm } 3329c6f9240SPeter Wemm if (p == NULL) 3339c6f9240SPeter Wemm break; 3349c6f9240SPeter Wemm if (p && p->fts_info == FTS_D && !dflag) { 3359c6f9240SPeter Wemm snprintf(xrefname, sizeof(xrefname), "%s/%s", 3369c6f9240SPeter Wemm ftsp->fts_path, xref_file); 3379ceddbd5SMarcel Moolenaar fxref = maketempfile(tempname, ftsp->fts_path); 3389c6f9240SPeter Wemm if (fxref == NULL) 3399c6f9240SPeter Wemm err(1, "can't create %s", tempname); 3409c6f9240SPeter Wemm ival = 1; 3419c6f9240SPeter Wemm fwrite(&ival, sizeof(ival), 1, fxref); 3429c6f9240SPeter Wemm reccnt = 0; 3439c6f9240SPeter Wemm } 3449c6f9240SPeter Wemm if (p->fts_info != FTS_F) 3459c6f9240SPeter Wemm continue; 3469f5529b4SRuslan Ermilov if (p->fts_namelen >= 8 && 3479f5529b4SRuslan Ermilov strcmp(p->fts_name + p->fts_namelen - 8, ".symbols") == 0) 3489f5529b4SRuslan Ermilov continue; 3499c6f9240SPeter Wemm read_kld(p->fts_path, p->fts_name); 3509c6f9240SPeter Wemm } 3519c6f9240SPeter Wemm fts_close(ftsp); 3529c6f9240SPeter Wemm return 0; 3539c6f9240SPeter Wemm } 3549c6f9240SPeter Wemm 3559c6f9240SPeter Wemm static void 3569c6f9240SPeter Wemm usage(void) 3579c6f9240SPeter Wemm { 3589c6f9240SPeter Wemm 3599c6f9240SPeter Wemm fprintf(stderr, "%s\n", 360cb40c7d1SRuslan Ermilov "usage: kldxref [-Rdv] [-f hintsfile] path ..." 3619c6f9240SPeter Wemm ); 3629c6f9240SPeter Wemm exit(1); 3639c6f9240SPeter Wemm } 364