1*9c6f9240SPeter Wemm /* 2*9c6f9240SPeter Wemm * Copyright (c) 2000, Boris Popov 3*9c6f9240SPeter Wemm * All rights reserved. 4*9c6f9240SPeter Wemm * 5*9c6f9240SPeter Wemm * Redistribution and use in source and binary forms, with or without 6*9c6f9240SPeter Wemm * modification, are permitted provided that the following conditions 7*9c6f9240SPeter Wemm * are met: 8*9c6f9240SPeter Wemm * 1. Redistributions of source code must retain the above copyright 9*9c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer. 10*9c6f9240SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 11*9c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer in the 12*9c6f9240SPeter Wemm * documentation and/or other materials provided with the distribution. 13*9c6f9240SPeter Wemm * 3. All advertising materials mentioning features or use of this software 14*9c6f9240SPeter Wemm * must display the following acknowledgement: 15*9c6f9240SPeter Wemm * This product includes software developed by Boris Popov. 16*9c6f9240SPeter Wemm * 4. Neither the name of the author nor the names of any co-contributors 17*9c6f9240SPeter Wemm * may be used to endorse or promote products derived from this software 18*9c6f9240SPeter Wemm * without specific prior written permission. 19*9c6f9240SPeter Wemm * 20*9c6f9240SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*9c6f9240SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*9c6f9240SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*9c6f9240SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*9c6f9240SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*9c6f9240SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*9c6f9240SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*9c6f9240SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*9c6f9240SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*9c6f9240SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*9c6f9240SPeter Wemm * SUCH DAMAGE. 31*9c6f9240SPeter Wemm * 32*9c6f9240SPeter Wemm * $FreeBSD$ 33*9c6f9240SPeter Wemm */ 34*9c6f9240SPeter Wemm 35*9c6f9240SPeter Wemm #include <sys/param.h> 36*9c6f9240SPeter Wemm #include <sys/exec.h> 37*9c6f9240SPeter Wemm #include <sys/queue.h> 38*9c6f9240SPeter Wemm #include <sys/kernel.h> 39*9c6f9240SPeter Wemm #include <sys/reboot.h> 40*9c6f9240SPeter Wemm #include <sys/linker.h> 41*9c6f9240SPeter Wemm #include <sys/stat.h> 42*9c6f9240SPeter Wemm #include <sys/module.h> 43*9c6f9240SPeter Wemm #define FREEBSD_ELF 44*9c6f9240SPeter Wemm #include <link.h> 45*9c6f9240SPeter Wemm #include <err.h> 46*9c6f9240SPeter Wemm #include <fts.h> 47*9c6f9240SPeter Wemm #include <string.h> 48*9c6f9240SPeter Wemm #include <machine/bootinfo.h> 49*9c6f9240SPeter Wemm #include <machine/elf.h> 50*9c6f9240SPeter Wemm #include <stdio.h> 51*9c6f9240SPeter Wemm #include <stdlib.h> 52*9c6f9240SPeter Wemm #include <unistd.h> 53*9c6f9240SPeter Wemm #include <errno.h> 54*9c6f9240SPeter Wemm 55*9c6f9240SPeter Wemm #include "ef.h" 56*9c6f9240SPeter Wemm 57*9c6f9240SPeter Wemm #define MAXRECSIZE 1024 58*9c6f9240SPeter Wemm #define check(val) if ((error = (val)) != 0) break 59*9c6f9240SPeter Wemm 60*9c6f9240SPeter Wemm #ifndef min 61*9c6f9240SPeter Wemm #define min(a,b) (((a)<(b)) ? (a) : (b)) 62*9c6f9240SPeter Wemm #endif 63*9c6f9240SPeter Wemm 64*9c6f9240SPeter Wemm struct mod_info { 65*9c6f9240SPeter Wemm char* mi_name; 66*9c6f9240SPeter Wemm int mi_ver; 67*9c6f9240SPeter Wemm SLIST_ENTRY(mod_info) mi_next; 68*9c6f9240SPeter Wemm }; 69*9c6f9240SPeter Wemm 70*9c6f9240SPeter Wemm #ifdef notnow 71*9c6f9240SPeter Wemm struct kld_info { 72*9c6f9240SPeter Wemm char* k_filename; 73*9c6f9240SPeter Wemm SLIST_HEAD(mod_list_head, mod_info) k_modules; 74*9c6f9240SPeter Wemm SLIST_ENTRY(kld_info) k_next; 75*9c6f9240SPeter Wemm }; 76*9c6f9240SPeter Wemm 77*9c6f9240SPeter Wemm SLIST_HEAD(kld_list_head, kld_info) kldlist; 78*9c6f9240SPeter Wemm #endif 79*9c6f9240SPeter Wemm 80*9c6f9240SPeter Wemm static int dflag, verbose; 81*9c6f9240SPeter Wemm 82*9c6f9240SPeter Wemm FILE *fxref; 83*9c6f9240SPeter Wemm 84*9c6f9240SPeter Wemm static char *xref_file = "linker.hints"; 85*9c6f9240SPeter Wemm 86*9c6f9240SPeter Wemm static char recbuf[MAXRECSIZE]; 87*9c6f9240SPeter Wemm static int recpos, reccnt; 88*9c6f9240SPeter Wemm 89*9c6f9240SPeter Wemm static void usage(void); 90*9c6f9240SPeter Wemm 91*9c6f9240SPeter Wemm static void 92*9c6f9240SPeter Wemm intalign(void) 93*9c6f9240SPeter Wemm { 94*9c6f9240SPeter Wemm recpos = (recpos + sizeof(int) - 1) & ~(sizeof(int) - 1); 95*9c6f9240SPeter Wemm } 96*9c6f9240SPeter Wemm 97*9c6f9240SPeter Wemm static void 98*9c6f9240SPeter Wemm record_start(void) 99*9c6f9240SPeter Wemm { 100*9c6f9240SPeter Wemm recpos = 0; 101*9c6f9240SPeter Wemm memset(recbuf, 0, MAXRECSIZE); 102*9c6f9240SPeter Wemm } 103*9c6f9240SPeter Wemm 104*9c6f9240SPeter Wemm static int 105*9c6f9240SPeter Wemm record_end(void) 106*9c6f9240SPeter Wemm { 107*9c6f9240SPeter Wemm if (dflag || recpos == 0) 108*9c6f9240SPeter Wemm return 0; 109*9c6f9240SPeter Wemm reccnt++; 110*9c6f9240SPeter Wemm intalign(); 111*9c6f9240SPeter Wemm fwrite(&recpos, sizeof(recpos), 1, fxref); 112*9c6f9240SPeter Wemm return fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0; 113*9c6f9240SPeter Wemm } 114*9c6f9240SPeter Wemm 115*9c6f9240SPeter Wemm static int 116*9c6f9240SPeter Wemm record_buf(const void *buf, int size) 117*9c6f9240SPeter Wemm { 118*9c6f9240SPeter Wemm if (MAXRECSIZE - recpos < size) 119*9c6f9240SPeter Wemm errx(1, "record buffer overflow"); 120*9c6f9240SPeter Wemm memcpy(recbuf + recpos, buf, size); 121*9c6f9240SPeter Wemm recpos += size; 122*9c6f9240SPeter Wemm return 0; 123*9c6f9240SPeter Wemm } 124*9c6f9240SPeter Wemm 125*9c6f9240SPeter Wemm static int 126*9c6f9240SPeter Wemm record_int(int val) 127*9c6f9240SPeter Wemm { 128*9c6f9240SPeter Wemm intalign(); 129*9c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 130*9c6f9240SPeter Wemm } 131*9c6f9240SPeter Wemm 132*9c6f9240SPeter Wemm static int 133*9c6f9240SPeter Wemm record_byte(u_char val) 134*9c6f9240SPeter Wemm { 135*9c6f9240SPeter Wemm return record_buf(&val, sizeof(val)); 136*9c6f9240SPeter Wemm } 137*9c6f9240SPeter Wemm 138*9c6f9240SPeter Wemm static int 139*9c6f9240SPeter Wemm record_string(const char *str) 140*9c6f9240SPeter Wemm { 141*9c6f9240SPeter Wemm int len = strlen(str); 142*9c6f9240SPeter Wemm int error; 143*9c6f9240SPeter Wemm 144*9c6f9240SPeter Wemm if (dflag) 145*9c6f9240SPeter Wemm return 0; 146*9c6f9240SPeter Wemm error = record_byte(len); 147*9c6f9240SPeter Wemm if (error) 148*9c6f9240SPeter Wemm return error; 149*9c6f9240SPeter Wemm return record_buf(str, len); 150*9c6f9240SPeter Wemm } 151*9c6f9240SPeter Wemm 152*9c6f9240SPeter Wemm static int 153*9c6f9240SPeter Wemm parse_entry(struct mod_metadata *md, const char *cval, 154*9c6f9240SPeter Wemm struct elf_file *ef, const char *kldname) 155*9c6f9240SPeter Wemm { 156*9c6f9240SPeter Wemm struct mod_depend mdp; 157*9c6f9240SPeter Wemm struct mod_version mdv; 158*9c6f9240SPeter Wemm Elf_Off data = (Elf_Off)md->md_data; 159*9c6f9240SPeter Wemm int error = 0; 160*9c6f9240SPeter Wemm 161*9c6f9240SPeter Wemm record_start(); 162*9c6f9240SPeter Wemm switch (md->md_type) { 163*9c6f9240SPeter Wemm case MDT_DEPEND: 164*9c6f9240SPeter Wemm if (!dflag) 165*9c6f9240SPeter Wemm break; 166*9c6f9240SPeter Wemm check(ef_seg_read(ef, data, sizeof(mdp), (void**)&mdp)); 167*9c6f9240SPeter Wemm printf(" depends on %s.%d (%d,%d)\n", cval, 168*9c6f9240SPeter Wemm mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum); 169*9c6f9240SPeter Wemm break; 170*9c6f9240SPeter Wemm case MDT_VERSION: 171*9c6f9240SPeter Wemm check(ef_seg_read(ef, data, sizeof(mdv), (void**)&mdv)); 172*9c6f9240SPeter Wemm record_int(MDT_VERSION); 173*9c6f9240SPeter Wemm record_string(cval); 174*9c6f9240SPeter Wemm record_int(mdv.mv_version); 175*9c6f9240SPeter Wemm record_string(kldname); 176*9c6f9240SPeter Wemm if (!dflag) 177*9c6f9240SPeter Wemm break; 178*9c6f9240SPeter Wemm printf(" interface %s.%d\n", cval, mdv.mv_version); 179*9c6f9240SPeter Wemm break; 180*9c6f9240SPeter Wemm case MDT_MODULE: 181*9c6f9240SPeter Wemm record_int(MDT_MODULE); 182*9c6f9240SPeter Wemm record_string(cval); 183*9c6f9240SPeter Wemm record_string(kldname); 184*9c6f9240SPeter Wemm if (!dflag) 185*9c6f9240SPeter Wemm break; 186*9c6f9240SPeter Wemm printf(" module %s\n", cval); 187*9c6f9240SPeter Wemm break; 188*9c6f9240SPeter Wemm default: 189*9c6f9240SPeter Wemm warnx("unknown metdata record %d in file %s", md->md_type, kldname); 190*9c6f9240SPeter Wemm } 191*9c6f9240SPeter Wemm if (!error) 192*9c6f9240SPeter Wemm record_end(); 193*9c6f9240SPeter Wemm return error; 194*9c6f9240SPeter Wemm } 195*9c6f9240SPeter Wemm 196*9c6f9240SPeter Wemm static int 197*9c6f9240SPeter Wemm read_kld(char *filename, char *kldname) 198*9c6f9240SPeter Wemm { 199*9c6f9240SPeter Wemm struct mod_metadata md; 200*9c6f9240SPeter Wemm struct elf_file ef; 201*9c6f9240SPeter Wemm /* struct kld_info *kip; 202*9c6f9240SPeter Wemm struct mod_info *mip;*/ 203*9c6f9240SPeter Wemm void **p, **orgp; 204*9c6f9240SPeter Wemm int error, nmlen; 205*9c6f9240SPeter Wemm long start, finish, entries; 206*9c6f9240SPeter Wemm Elf_Sym *sym; 207*9c6f9240SPeter Wemm char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp; 208*9c6f9240SPeter Wemm 209*9c6f9240SPeter Wemm if (verbose || dflag) 210*9c6f9240SPeter Wemm printf("%s\n", filename); 211*9c6f9240SPeter Wemm error = ef_open(filename, &ef, verbose); 212*9c6f9240SPeter Wemm if (error) 213*9c6f9240SPeter Wemm return error; 214*9c6f9240SPeter Wemm if (ef.ef_type != EFT_KLD && ef.ef_type != EFT_KERNEL) { 215*9c6f9240SPeter Wemm ef_close(&ef); 216*9c6f9240SPeter Wemm return 0; 217*9c6f9240SPeter Wemm } 218*9c6f9240SPeter Wemm if (!dflag) { 219*9c6f9240SPeter Wemm cp = strrchr(kldname, '.'); 220*9c6f9240SPeter Wemm nmlen = cp ? min(MAXMODNAME, cp - kldname) : 221*9c6f9240SPeter Wemm min(MAXMODNAME, strlen(kldname)); 222*9c6f9240SPeter Wemm strncpy(kldmodname, kldname, nmlen); 223*9c6f9240SPeter Wemm kldmodname[nmlen] = '\0'; 224*9c6f9240SPeter Wemm /* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/ 225*9c6f9240SPeter Wemm } 226*9c6f9240SPeter Wemm do { 227*9c6f9240SPeter Wemm check(ef_lookup_symbol(&ef, "__start_set_" MDT_SETNAME, &sym)); 228*9c6f9240SPeter Wemm start = sym->st_value; 229*9c6f9240SPeter Wemm check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym)); 230*9c6f9240SPeter Wemm finish = sym->st_value; 231*9c6f9240SPeter Wemm entries = (finish - start) / sizeof(void *); 232*9c6f9240SPeter Wemm check(ef_seg_read_entry(&ef, start, sizeof(*p) * entries, (void**)&p)); 233*9c6f9240SPeter Wemm orgp = p; 234*9c6f9240SPeter Wemm while(entries--) { 235*9c6f9240SPeter Wemm check(ef_seg_read(&ef, (Elf_Off)*p, sizeof(md), &md)); 236*9c6f9240SPeter Wemm p++; 237*9c6f9240SPeter Wemm check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); 238*9c6f9240SPeter Wemm cval[MAXMODNAME] = '\0'; 239*9c6f9240SPeter Wemm parse_entry(&md, cval, &ef, kldname); 240*9c6f9240SPeter Wemm } 241*9c6f9240SPeter Wemm if (error) 242*9c6f9240SPeter Wemm warnc(error, "error while reading %s", filename); 243*9c6f9240SPeter Wemm free(orgp); 244*9c6f9240SPeter Wemm } while(0); 245*9c6f9240SPeter Wemm ef_close(&ef); 246*9c6f9240SPeter Wemm return error; 247*9c6f9240SPeter Wemm } 248*9c6f9240SPeter Wemm 249*9c6f9240SPeter Wemm void 250*9c6f9240SPeter Wemm maketempfile(char *dest, const char *root) 251*9c6f9240SPeter Wemm { 252*9c6f9240SPeter Wemm char *p; 253*9c6f9240SPeter Wemm 254*9c6f9240SPeter Wemm strncpy(dest, root, MAXPATHLEN - 1); 255*9c6f9240SPeter Wemm dest[MAXPATHLEN] = '\0'; 256*9c6f9240SPeter Wemm 257*9c6f9240SPeter Wemm if ((p = strrchr(dest, '/')) != 0) 258*9c6f9240SPeter Wemm p++; 259*9c6f9240SPeter Wemm else 260*9c6f9240SPeter Wemm p = dest; 261*9c6f9240SPeter Wemm strcpy(p, "lhint.XXXXXX"); 262*9c6f9240SPeter Wemm if (mkstemp(dest) == -1) 263*9c6f9240SPeter Wemm err(1, "%s", dest); 264*9c6f9240SPeter Wemm } 265*9c6f9240SPeter Wemm 266*9c6f9240SPeter Wemm static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; 267*9c6f9240SPeter Wemm 268*9c6f9240SPeter Wemm int 269*9c6f9240SPeter Wemm main(int argc, char *argv[]) 270*9c6f9240SPeter Wemm { 271*9c6f9240SPeter Wemm FTS *ftsp; 272*9c6f9240SPeter Wemm FTSENT *p; 273*9c6f9240SPeter Wemm int opt, fts_options, ival; 274*9c6f9240SPeter Wemm 275*9c6f9240SPeter Wemm fts_options = FTS_PHYSICAL; 276*9c6f9240SPeter Wemm /* SLIST_INIT(&kldlist);*/ 277*9c6f9240SPeter Wemm 278*9c6f9240SPeter Wemm while ((opt = getopt(argc, argv, "Rdf:v")) != -1) { 279*9c6f9240SPeter Wemm switch (opt) { 280*9c6f9240SPeter Wemm case 'd': 281*9c6f9240SPeter Wemm dflag = 1; 282*9c6f9240SPeter Wemm break; 283*9c6f9240SPeter Wemm case 'f': 284*9c6f9240SPeter Wemm xref_file = optarg; 285*9c6f9240SPeter Wemm break; 286*9c6f9240SPeter Wemm case 'v': 287*9c6f9240SPeter Wemm verbose++; 288*9c6f9240SPeter Wemm break; 289*9c6f9240SPeter Wemm case 'R': 290*9c6f9240SPeter Wemm fts_options |= FTS_COMFOLLOW; 291*9c6f9240SPeter Wemm break; 292*9c6f9240SPeter Wemm default: 293*9c6f9240SPeter Wemm usage(); 294*9c6f9240SPeter Wemm /* NOTREACHED */ 295*9c6f9240SPeter Wemm } 296*9c6f9240SPeter Wemm } 297*9c6f9240SPeter Wemm if (argc - optind < 1) 298*9c6f9240SPeter Wemm usage(); 299*9c6f9240SPeter Wemm argc -= optind; 300*9c6f9240SPeter Wemm argv += optind; 301*9c6f9240SPeter Wemm 302*9c6f9240SPeter Wemm ftsp = fts_open(argv, fts_options, 0); 303*9c6f9240SPeter Wemm if (ftsp == NULL) 304*9c6f9240SPeter Wemm exit(1); 305*9c6f9240SPeter Wemm 306*9c6f9240SPeter Wemm for (;;) { 307*9c6f9240SPeter Wemm p = fts_read(ftsp); 308*9c6f9240SPeter Wemm if ((p == NULL || p->fts_info == FTS_D) && !dflag && fxref) { 309*9c6f9240SPeter Wemm fclose(fxref); 310*9c6f9240SPeter Wemm if (reccnt) { 311*9c6f9240SPeter Wemm rename(tempname, xrefname); 312*9c6f9240SPeter Wemm } else { 313*9c6f9240SPeter Wemm unlink(tempname); 314*9c6f9240SPeter Wemm unlink(xrefname); 315*9c6f9240SPeter Wemm } 316*9c6f9240SPeter Wemm } 317*9c6f9240SPeter Wemm if (p == NULL) 318*9c6f9240SPeter Wemm break; 319*9c6f9240SPeter Wemm if (p && p->fts_info == FTS_D && !dflag) { 320*9c6f9240SPeter Wemm snprintf(xrefname, sizeof(xrefname), "%s/%s", 321*9c6f9240SPeter Wemm ftsp->fts_path, xref_file); 322*9c6f9240SPeter Wemm maketempfile(tempname, ftsp->fts_path); 323*9c6f9240SPeter Wemm fxref = fopen(tempname, "w+t"); 324*9c6f9240SPeter Wemm if (fxref == NULL) 325*9c6f9240SPeter Wemm err(1, "can't create %s", tempname); 326*9c6f9240SPeter Wemm ival = 1; 327*9c6f9240SPeter Wemm fwrite(&ival, sizeof(ival), 1, fxref); 328*9c6f9240SPeter Wemm reccnt = 0; 329*9c6f9240SPeter Wemm } 330*9c6f9240SPeter Wemm if (p->fts_info != FTS_F) 331*9c6f9240SPeter Wemm continue; 332*9c6f9240SPeter Wemm read_kld(p->fts_path, p->fts_name); 333*9c6f9240SPeter Wemm } 334*9c6f9240SPeter Wemm fts_close(ftsp); 335*9c6f9240SPeter Wemm return 0; 336*9c6f9240SPeter Wemm } 337*9c6f9240SPeter Wemm 338*9c6f9240SPeter Wemm static void 339*9c6f9240SPeter Wemm usage(void) 340*9c6f9240SPeter Wemm { 341*9c6f9240SPeter Wemm 342*9c6f9240SPeter Wemm fprintf(stderr, "%s\n", 343*9c6f9240SPeter Wemm "Usage: kldxref [-Rdv] [-f hintfile] path [path..]" 344*9c6f9240SPeter Wemm ); 345*9c6f9240SPeter Wemm exit(1); 346*9c6f9240SPeter Wemm } 347